Merge pull request #33569 from akien-mga/3.1

Assorted cherry-picks from the master branch for Godot 3.1.2 [4th batch]
This commit is contained in:
Rémi Verschelde 2019-11-12 15:45:30 +01:00 committed by GitHub
commit 7f6e2c5037
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
395 changed files with 15990 additions and 8841 deletions

View file

@ -165,7 +165,7 @@ License: FTL
Files: ./thirdparty/glad/ Files: ./thirdparty/glad/
Comment: glad Comment: glad
Copyright: 2013-2018, David Herberth Copyright: 2013-2019, David Herberth
License: Expat License: Expat
Files: ./thirdparty/jpeg_compressor/ Files: ./thirdparty/jpeg_compressor/
@ -321,7 +321,7 @@ License: BSD-3-clause
Files: ./thirdparty/misc/stb_truetype.h Files: ./thirdparty/misc/stb_truetype.h
./thirdparty/misc/stb_vorbis.c ./thirdparty/misc/stb_vorbis.c
Comment: stb libraries Comment: stb libraries
Copyright: 2007-2017, Sean Barrett Copyright: 2007-2019, Sean Barrett
License: public-domain License: public-domain
Files: ./thirdparty/misc/triangulator.cpp Files: ./thirdparty/misc/triangulator.cpp
@ -350,8 +350,8 @@ License: BSD-3-clause
Files: ./thirdparty/pcre2/ Files: ./thirdparty/pcre2/
Comment: PCRE2 Comment: PCRE2
Copyright: 1997-2018, University of Cambridge, Copyright: 1997-2019, University of Cambridge,
2009-2018, Zoltan Herczeg 2009-2019, Zoltan Herczeg
License: BSD-3-clause License: BSD-3-clause
Files: ./thirdparty/pvrtccompressor/ Files: ./thirdparty/pvrtccompressor/
@ -371,7 +371,7 @@ License: Expat
Files: ./thirdparty/tinyexr/ Files: ./thirdparty/tinyexr/
Comment: TinyEXR Comment: TinyEXR
Copyright: 2014-2018, Syoyo Fujita Copyright: 2014-2019, Syoyo Fujita
2002, Industrial Light & Magic, a division of Lucas Digital Ltd. LLC 2002, Industrial Light & Magic, a division of Lucas Digital Ltd. LLC
License: BSD-3-clause License: BSD-3-clause

View file

@ -121,6 +121,8 @@ if env['builtin_zstd']:
"compress/zstd_ldm.c", "compress/zstd_ldm.c",
"compress/zstd_opt.c", "compress/zstd_opt.c",
"compress/zstdmt_compress.c", "compress/zstdmt_compress.c",
"compress/zstd_compress_literals.c",
"compress/zstd_compress_sequences.c",
"decompress/huf_decompress.c", "decompress/huf_decompress.c",
"decompress/zstd_ddict.c", "decompress/zstd_ddict.c",
"decompress/zstd_decompress_block.c", "decompress/zstd_decompress_block.c",

View file

@ -346,6 +346,12 @@ Error HTTPClient::poll() {
} else { } else {
// We are already handshaking, which means we can use your already active SSL connection // We are already handshaking, which means we can use your already active SSL connection
ssl = static_cast<Ref<StreamPeerSSL> >(connection); ssl = static_cast<Ref<StreamPeerSSL> >(connection);
if (ssl.is_null()) {
close();
status = STATUS_SSL_HANDSHAKE_ERROR;
return ERR_CANT_CONNECT;
}
ssl->poll(); // Try to finish the handshake ssl->poll(); // Try to finish the handshake
} }

View file

@ -1230,11 +1230,15 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
buf += 4; buf += 4;
PoolVector<uint8_t>::Read r = data.read(); PoolVector<uint8_t>::Read r = data.read();
copymem(buf, &r[0], datalen * datasize); copymem(buf, &r[0], datalen * datasize);
buf += datalen * datasize;
} }
r_len += 4 + datalen * datasize; r_len += 4 + datalen * datasize;
while (r_len % 4) while (r_len % 4) {
r_len++; r_len++;
if (buf)
*(buf++) = 0;
}
} break; } break;
case Variant::POOL_INT_ARRAY: { case Variant::POOL_INT_ARRAY: {

View file

@ -283,8 +283,9 @@ void MultiplayerAPI::_process_rpc(Node *p_node, const StringName &p_name, int p_
rpc_mode = p_node->get_script_instance()->get_rpc_mode(p_name); rpc_mode = p_node->get_script_instance()->get_rpc_mode(p_name);
} }
ERR_EXPLAIN("RPC '" + String(p_name) + "' is not allowed from: " + itos(p_from) + ". Mode is " + itos((int)rpc_mode) + ", master is " + itos(p_node->get_network_master()) + "."); bool can_call = _can_call_mode(p_node, rpc_mode, p_from);
ERR_FAIL_COND(!_can_call_mode(p_node, rpc_mode, p_from)); ERR_EXPLAIN("RPC '" + String(p_name) + "' is not allowed on node " + p_node->get_path() + " from: " + itos(p_from) + ". Mode is " + itos((int)rpc_mode) + ", master is " + itos(p_node->get_network_master()) + ".");
ERR_FAIL_COND(!can_call);
int argc = p_packet[p_offset]; int argc = p_packet[p_offset];
Vector<Variant> args; Vector<Variant> args;
@ -332,8 +333,9 @@ void MultiplayerAPI::_process_rset(Node *p_node, const StringName &p_name, int p
rset_mode = p_node->get_script_instance()->get_rset_mode(p_name); rset_mode = p_node->get_script_instance()->get_rset_mode(p_name);
} }
ERR_EXPLAIN("RSET '" + String(p_name) + "' is not allowed from: " + itos(p_from) + ". Mode is " + itos((int)rset_mode) + ", master is " + itos(p_node->get_network_master()) + "."); bool can_call = _can_call_mode(p_node, rset_mode, p_from);
ERR_FAIL_COND(!_can_call_mode(p_node, rset_mode, p_from)); ERR_EXPLAIN("RSET '" + String(p_name) + "' is not allowed on node " + p_node->get_path() + " from: " + itos(p_from) + ". Mode is " + itos((int)rset_mode) + ", master is " + itos(p_node->get_network_master()) + ".");
ERR_FAIL_COND(!can_call);
Variant value; Variant value;
Error err = decode_variant(value, &p_packet[p_offset], p_packet_len - p_offset, NULL, allow_object_decoding || network_peer->is_object_decoding_allowed()); Error err = decode_variant(value, &p_packet[p_offset], p_packet_len - p_offset, NULL, allow_object_decoding || network_peer->is_object_decoding_allowed());

View file

@ -702,9 +702,11 @@ public:
/* if we can assume that the line segment starts outside the circle (e.g. for continuous time collision detection) then the following can be skipped and we can just return the equivalent of res1 */ /* if we can assume that the line segment starts outside the circle (e.g. for continuous time collision detection) then the following can be skipped and we can just return the equivalent of res1 */
sqrtterm = Math::sqrt(sqrtterm); sqrtterm = Math::sqrt(sqrtterm);
real_t res1 = (-b - sqrtterm) / (2 * a); real_t res1 = (-b - sqrtterm) / (2 * a);
//real_t res2 = ( -b + sqrtterm ) / (2 * a); real_t res2 = (-b + sqrtterm) / (2 * a);
return (res1 >= 0 && res1 <= 1) ? res1 : -1; if (res1 >= 0 && res1 <= 1) return res1;
if (res2 >= 0 && res2 <= 1) return res2;
return -1;
} }
static inline Vector<Vector3> clip_polygon(const Vector<Vector3> &polygon, const Plane &p_plane) { static inline Vector<Vector3> clip_polygon(const Vector<Vector3> &polygon, const Plane &p_plane) {

View file

@ -218,12 +218,8 @@ Vector3 Vector3::linear_interpolate(const Vector3 &p_b, real_t p_t) const {
} }
Vector3 Vector3::slerp(const Vector3 &p_b, real_t p_t) const { Vector3 Vector3::slerp(const Vector3 &p_b, real_t p_t) const {
#ifdef MATH_CHECKS
ERR_FAIL_COND_V(!is_normalized(), Vector3());
#endif
real_t theta = angle_to(p_b); real_t theta = angle_to(p_b);
return rotated(cross(p_b), theta * p_t); return rotated(cross(p_b).normalized(), theta * p_t);
} }
real_t Vector3::distance_to(const Vector3 &p_b) const { real_t Vector3::distance_to(const Vector3 &p_b) const {

View file

@ -302,10 +302,6 @@ void MessageQueue::flush() {
_call_function(target, message->target, args, message->args, message->type & FLAG_SHOW_ERROR); _call_function(target, message->target, args, message->args, message->type & FLAG_SHOW_ERROR);
for (int i = 0; i < message->args; i++) {
args[i].~Variant();
}
} break; } break;
case TYPE_NOTIFICATION: { case TYPE_NOTIFICATION: {
@ -319,11 +315,17 @@ void MessageQueue::flush() {
// messages don't expect a return value // messages don't expect a return value
target->set(message->target, *arg); target->set(message->target, *arg);
arg->~Variant();
} break; } break;
} }
} }
if ((message->type & FLAG_MASK) != TYPE_NOTIFICATION) {
Variant *args = (Variant *)(message + 1);
for (int i = 0; i < message->args; i++) {
args[i].~Variant();
}
}
message->~Message(); message->~Message();
_THREAD_SAFE_LOCK_ _THREAD_SAFE_LOCK_

View file

@ -608,18 +608,16 @@ Variant Object::get_indexed(const Vector<StringName> &p_names, bool *r_valid) co
} }
bool valid = false; bool valid = false;
Variant current_value = get(p_names[0]); Variant current_value = get(p_names[0], &valid);
for (int i = 1; i < p_names.size(); i++) { for (int i = 1; i < p_names.size(); i++) {
current_value = current_value.get_named(p_names[i], &valid); current_value = current_value.get_named(p_names[i], &valid);
if (!valid) { if (!valid)
if (r_valid) break;
*r_valid = false;
return Variant();
}
} }
if (r_valid) if (r_valid)
*r_valid = true; *r_valid = valid;
return current_value; return current_value;
} }

View file

@ -779,8 +779,13 @@ public:
static int get_object_count(); static int get_object_count();
_FORCE_INLINE_ static bool instance_validate(Object *p_ptr) { _FORCE_INLINE_ static bool instance_validate(Object *p_ptr) {
rw_lock->read_lock();
return instance_checks.has(p_ptr); bool exists = instance_checks.has(p_ptr);
rw_lock->read_unlock();
return exists;
} }
}; };

View file

@ -90,6 +90,7 @@ void Input::_bind_methods() {
ClassDB::bind_method(D_METHOD("action_press", "action", "strength"), &Input::action_press, DEFVAL(1.f)); ClassDB::bind_method(D_METHOD("action_press", "action", "strength"), &Input::action_press, DEFVAL(1.f));
ClassDB::bind_method(D_METHOD("action_release", "action"), &Input::action_release); ClassDB::bind_method(D_METHOD("action_release", "action"), &Input::action_release);
ClassDB::bind_method(D_METHOD("set_default_cursor_shape", "shape"), &Input::set_default_cursor_shape, DEFVAL(CURSOR_ARROW)); ClassDB::bind_method(D_METHOD("set_default_cursor_shape", "shape"), &Input::set_default_cursor_shape, DEFVAL(CURSOR_ARROW));
ClassDB::bind_method(D_METHOD("get_current_cursor_shape"), &Input::get_current_cursor_shape);
ClassDB::bind_method(D_METHOD("set_custom_mouse_cursor", "image", "shape", "hotspot"), &Input::set_custom_mouse_cursor, DEFVAL(CURSOR_ARROW), DEFVAL(Vector2())); ClassDB::bind_method(D_METHOD("set_custom_mouse_cursor", "image", "shape", "hotspot"), &Input::set_custom_mouse_cursor, DEFVAL(CURSOR_ARROW), DEFVAL(Vector2()));
ClassDB::bind_method(D_METHOD("parse_input_event", "event"), &Input::parse_input_event); ClassDB::bind_method(D_METHOD("parse_input_event", "event"), &Input::parse_input_event);
ClassDB::bind_method(D_METHOD("set_use_accumulated_input", "enable"), &Input::set_use_accumulated_input); ClassDB::bind_method(D_METHOD("set_use_accumulated_input", "enable"), &Input::set_use_accumulated_input);

View file

@ -122,10 +122,10 @@ public:
virtual bool is_emulating_touch_from_mouse() const = 0; virtual bool is_emulating_touch_from_mouse() const = 0;
virtual bool is_emulating_mouse_from_touch() const = 0; virtual bool is_emulating_mouse_from_touch() const = 0;
virtual CursorShape get_default_cursor_shape() = 0; virtual CursorShape get_default_cursor_shape() const = 0;
virtual void set_default_cursor_shape(CursorShape p_shape) = 0; virtual void set_default_cursor_shape(CursorShape p_shape) = 0;
virtual CursorShape get_current_cursor_shape() const = 0;
virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape = CURSOR_ARROW, const Vector2 &p_hotspot = Vector2()) = 0; virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape = CURSOR_ARROW, const Vector2 &p_hotspot = Vector2()) = 0;
virtual void set_mouse_in_window(bool p_in_window) = 0;
virtual String get_joy_button_string(int p_button) = 0; virtual String get_joy_button_string(int p_button) = 0;
virtual String get_joy_axis_string(int p_axis) = 0; virtual String get_joy_axis_string(int p_axis) = 0;

View file

@ -717,8 +717,17 @@ bool InputEventJoypadMotion::action_match(const Ref<InputEvent> &p_event, bool *
bool pressed = same_direction ? Math::abs(jm->get_axis_value()) >= p_deadzone : false; bool pressed = same_direction ? Math::abs(jm->get_axis_value()) >= p_deadzone : false;
if (p_pressed != NULL) if (p_pressed != NULL)
*p_pressed = pressed; *p_pressed = pressed;
if (p_strength != NULL) if (p_strength != NULL) {
*p_strength = pressed ? CLAMP(Math::inverse_lerp(p_deadzone, 1.0f, Math::abs(jm->get_axis_value())), 0.0f, 1.0f) : 0.0f; if (pressed) {
if (p_deadzone == 1.0f) {
*p_strength = 1.0f;
} else {
*p_strength = CLAMP(Math::inverse_lerp(p_deadzone, 1.0f, Math::abs(jm->get_axis_value())), 0.0f, 1.0f);
}
} else {
*p_strength = 0.0f;
}
}
} }
return match; return match;
} }

View file

@ -225,6 +225,16 @@ int OS::get_virtual_keyboard_height() const {
return 0; return 0;
} }
void OS::set_cursor_shape(CursorShape p_shape) {
}
OS::CursorShape OS::get_cursor_shape() const {
return CURSOR_ARROW;
}
void OS::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
}
void OS::print_all_resources(String p_to_file) { void OS::print_all_resources(String p_to_file) {
ERR_FAIL_COND(p_to_file != "" && _OSPRF); ERR_FAIL_COND(p_to_file != "" && _OSPRF);

View file

@ -378,8 +378,9 @@ public:
// returns height of the currently shown virtual keyboard (0 if keyboard is hidden) // returns height of the currently shown virtual keyboard (0 if keyboard is hidden)
virtual int get_virtual_keyboard_height() const; virtual int get_virtual_keyboard_height() const;
virtual void set_cursor_shape(CursorShape p_shape) = 0; virtual void set_cursor_shape(CursorShape p_shape);
virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) = 0; virtual CursorShape get_cursor_shape() const;
virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
virtual bool get_swap_ok_cancel() { return false; } virtual bool get_swap_ok_cancel() { return false; }
virtual void dump_memory_to_file(const char *p_file); virtual void dump_memory_to_file(const char *p_file);

View file

@ -179,6 +179,7 @@ static const char *locale_list[] = {
"ff_SN", // Fulah (Senegal) "ff_SN", // Fulah (Senegal)
"fi", // Finnish "fi", // Finnish
"fi_FI", // Finnish (Finland) "fi_FI", // Finnish (Finland)
"fil", // Filipino
"fil_PH", // Filipino (Philippines) "fil_PH", // Filipino (Philippines)
"fo_FO", // Faroese (Faroe Islands) "fo_FO", // Faroese (Faroe Islands)
"fr", // French "fr", // French
@ -227,6 +228,7 @@ static const char *locale_list[] = {
"ja", // Japanese "ja", // Japanese
"ja_JP", // Japanese (Japan) "ja_JP", // Japanese (Japan)
"kab_DZ", // Kabyle (Algeria) "kab_DZ", // Kabyle (Algeria)
"ka", // Georgian
"ka_GE", // Georgian (Georgia) "ka_GE", // Georgian (Georgia)
"kk_KZ", // Kazakh (Kazakhstan) "kk_KZ", // Kazakh (Kazakhstan)
"kl_GL", // Kalaallisut (Greenland) "kl_GL", // Kalaallisut (Greenland)
@ -257,10 +259,12 @@ static const char *locale_list[] = {
"mg_MG", // Malagasy (Madagascar) "mg_MG", // Malagasy (Madagascar)
"mh_MH", // Marshallese (Marshall Islands) "mh_MH", // Marshallese (Marshall Islands)
"mhr_RU", // Eastern Mari (Russia) "mhr_RU", // Eastern Mari (Russia)
"mi_NZ", // Maori (New Zealand) "mi", // Māori
"mi_NZ", // Māori (New Zealand)
"miq_NI", // Mískito (Nicaragua) "miq_NI", // Mískito (Nicaragua)
"mk", // Macedonian "mk", // Macedonian
"mk_MK", // Macedonian (Macedonia) "mk_MK", // Macedonian (Macedonia)
"ml", // Malayalam
"ml_IN", // Malayalam (India) "ml_IN", // Malayalam (India)
"mni_IN", // Manipuri (India) "mni_IN", // Manipuri (India)
"mn_MN", // Mongolian (Mongolia) "mn_MN", // Mongolian (Mongolia)
@ -326,6 +330,7 @@ static const char *locale_list[] = {
"sgs_LT", // Samogitian (Lithuania) "sgs_LT", // Samogitian (Lithuania)
"shs_CA", // Shuswap (Canada) "shs_CA", // Shuswap (Canada)
"sid_ET", // Sidamo (Ethiopia) "sid_ET", // Sidamo (Ethiopia)
"si", // Sinhala
"si_LK", // Sinhala (Sri Lanka) "si_LK", // Sinhala (Sri Lanka)
"sk", // Slovak "sk", // Slovak
"sk_SK", // Slovak (Slovakia) "sk_SK", // Slovak (Slovakia)
@ -343,6 +348,7 @@ static const char *locale_list[] = {
"sq_MK", // Albanian (Macedonia) "sq_MK", // Albanian (Macedonia)
"sr", // Serbian "sr", // Serbian
"sr_Cyrl", // Serbian (Cyrillic) "sr_Cyrl", // Serbian (Cyrillic)
"sr_Latn", // Serbian (Latin)
"sr_ME", // Serbian (Montenegro) "sr_ME", // Serbian (Montenegro)
"sr_RS", // Serbian (Serbia) "sr_RS", // Serbian (Serbia)
"ss_ZA", // Swati (South Africa) "ss_ZA", // Swati (South Africa)
@ -357,6 +363,7 @@ static const char *locale_list[] = {
"ta_IN", // Tamil (India) "ta_IN", // Tamil (India)
"ta_LK", // Tamil (Sri Lanka) "ta_LK", // Tamil (Sri Lanka)
"tcy_IN", // Tulu (India) "tcy_IN", // Tulu (India)
"te", // Telugu
"te_IN", // Telugu (India) "te_IN", // Telugu (India)
"tg_TJ", // Tajik (Tajikistan) "tg_TJ", // Tajik (Tajikistan)
"the_NP", // Chitwania Tharu (Nepal) "the_NP", // Chitwania Tharu (Nepal)
@ -540,6 +547,7 @@ static const char *locale_names[] = {
"Fulah (Senegal)", "Fulah (Senegal)",
"Finnish", "Finnish",
"Finnish (Finland)", "Finnish (Finland)",
"Filipino",
"Filipino (Philippines)", "Filipino (Philippines)",
"Faroese (Faroe Islands)", "Faroese (Faroe Islands)",
"French", "French",
@ -588,6 +596,7 @@ static const char *locale_names[] = {
"Japanese", "Japanese",
"Japanese (Japan)", "Japanese (Japan)",
"Kabyle (Algeria)", "Kabyle (Algeria)",
"Georgian",
"Georgian (Georgia)", "Georgian (Georgia)",
"Kazakh (Kazakhstan)", "Kazakh (Kazakhstan)",
"Kalaallisut (Greenland)", "Kalaallisut (Greenland)",
@ -618,10 +627,12 @@ static const char *locale_names[] = {
"Malagasy (Madagascar)", "Malagasy (Madagascar)",
"Marshallese (Marshall Islands)", "Marshallese (Marshall Islands)",
"Eastern Mari (Russia)", "Eastern Mari (Russia)",
"Maori (New Zealand)", "Māori",
"Māori (New Zealand)",
"Mískito (Nicaragua)", "Mískito (Nicaragua)",
"Macedonian", "Macedonian",
"Macedonian (Macedonia)", "Macedonian (Macedonia)",
"Malayalam",
"Malayalam (India)", "Malayalam (India)",
"Manipuri (India)", "Manipuri (India)",
"Mongolian (Mongolia)", "Mongolian (Mongolia)",
@ -687,6 +698,7 @@ static const char *locale_names[] = {
"Samogitian (Lithuania)", "Samogitian (Lithuania)",
"Shuswap (Canada)", "Shuswap (Canada)",
"Sidamo (Ethiopia)", "Sidamo (Ethiopia)",
"Sinhala",
"Sinhala (Sri Lanka)", "Sinhala (Sri Lanka)",
"Slovak", "Slovak",
"Slovak (Slovakia)", "Slovak (Slovakia)",
@ -704,6 +716,7 @@ static const char *locale_names[] = {
"Albanian (Macedonia)", "Albanian (Macedonia)",
"Serbian", "Serbian",
"Serbian (Cyrillic)", "Serbian (Cyrillic)",
"Serbian (Latin)",
"Serbian (Montenegro)", "Serbian (Montenegro)",
"Serbian (Serbia)", "Serbian (Serbia)",
"Swati (South Africa)", "Swati (South Africa)",
@ -718,6 +731,7 @@ static const char *locale_names[] = {
"Tamil (India)", "Tamil (India)",
"Tamil (Sri Lanka)", "Tamil (Sri Lanka)",
"Tulu (India)", "Tulu (India)",
"Telugu",
"Telugu (India)", "Telugu (India)",
"Tajik (Tajikistan)", "Tajik (Tajikistan)",
"Chitwania Tharu (Nepal)", "Chitwania Tharu (Nepal)",

View file

@ -21,6 +21,12 @@
<description> <description>
</description> </description>
</method> </method>
<method name="_export_end" qualifiers="virtual">
<return type="void">
</return>
<description>
</description>
</method>
<method name="_export_file" qualifiers="virtual"> <method name="_export_file" qualifiers="virtual">
<return type="void"> <return type="void">
</return> </return>

View file

@ -214,14 +214,19 @@
Use with [method set_param], [method set_param_randomness], and [method set_param_texture] to set animation offset properties. Use with [method set_param], [method set_param_randomness], and [method set_param_texture] to set animation offset properties.
</constant> </constant>
<constant name="PARAM_MAX" value="12" enum="Parameter"> <constant name="PARAM_MAX" value="12" enum="Parameter">
Represents the size of the [enum Parameter] enum.
</constant> </constant>
<constant name="FLAG_ALIGN_Y_TO_VELOCITY" value="0" enum="Flags"> <constant name="FLAG_ALIGN_Y_TO_VELOCITY" value="0" enum="Flags">
Use with [method set_flag] to set [member flag_align_y]. Use with [method set_flag] to set [member flag_align_y].
</constant> </constant>
<constant name="FLAG_ROTATE_Y" value="1" enum="Flags"> <constant name="FLAG_ROTATE_Y" value="1" enum="Flags">
Use with [method set_flag] to set [member flag_rotate_y] Use with [method set_flag] to set [member flag_rotate_y].
</constant>
<constant name="FLAG_DISABLE_Z" value="2" enum="Flags">
Use with [method set_flag] to set [member flag_disable_z].
</constant> </constant>
<constant name="FLAG_MAX" value="3" enum="Flags"> <constant name="FLAG_MAX" value="3" enum="Flags">
Represents the size of the [enum Flags] enum.
</constant> </constant>
<constant name="EMISSION_SHAPE_POINT" value="0" enum="EmissionShape"> <constant name="EMISSION_SHAPE_POINT" value="0" enum="EmissionShape">
All particles will be emitted from a single point. All particles will be emitted from a single point.

View file

@ -321,6 +321,12 @@
<constant name="HALF_OFFSET_DISABLED" value="2" enum="HalfOffset"> <constant name="HALF_OFFSET_DISABLED" value="2" enum="HalfOffset">
Half offset disabled. Half offset disabled.
</constant> </constant>
<constant name="HALF_OFFSET_NEGATIVE_X" value="3" enum="HalfOffset">
Half offset on the X coordinate (negative).
</constant>
<constant name="HALF_OFFSET_NEGATIVE_Y" value="4" enum="HalfOffset">
Half offset on the Y coordinate (negative).
</constant>
<constant name="TILE_ORIGIN_TOP_LEFT" value="0" enum="TileOrigin"> <constant name="TILE_ORIGIN_TOP_LEFT" value="0" enum="TileOrigin">
Tile origin at its top-left corner. Tile origin at its top-left corner.
</constant> </constant>

View file

@ -1110,8 +1110,8 @@ void RasterizerSceneGLES2::_add_geometry_with_material(RasterizerStorageGLES2::G
LightInstance *li = light_instance_owner.getornull(e->instance->light_instances[i]); LightInstance *li = light_instance_owner.getornull(e->instance->light_instances[i]);
if (li->light_index >= render_light_instance_count) { if (li->light_index >= render_light_instance_count || render_light_instances[li->light_index] != li) {
continue; // too many continue; // too many or light_index did not correspond to the light instances to be rendered
} }
if (copy) { if (copy) {

View file

@ -2354,7 +2354,7 @@ void RasterizerSceneGLES3::_add_geometry_with_material(RasterizerStorageGLES3::G
if (p_depth_pass) { if (p_depth_pass) {
if (has_blend_alpha || p_material->shader->spatial.uses_depth_texture || (has_base_alpha && p_material->shader->spatial.depth_draw_mode != RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) || p_material->shader->spatial.depth_draw_mode == RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_NEVER || p_material->shader->spatial.no_depth_test) if (has_blend_alpha || p_material->shader->spatial.uses_depth_texture || (has_base_alpha && p_material->shader->spatial.depth_draw_mode != RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) || p_material->shader->spatial.depth_draw_mode == RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_NEVER || p_material->shader->spatial.no_depth_test || p_instance->cast_shadows == VS::SHADOW_CASTING_SETTING_OFF)
return; //bye return; //bye
if (!p_material->shader->spatial.uses_alpha_scissor && !p_material->shader->spatial.writes_modelview_or_projection && !p_material->shader->spatial.uses_vertex && !p_material->shader->spatial.uses_discard && p_material->shader->spatial.depth_draw_mode != RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) { if (!p_material->shader->spatial.uses_alpha_scissor && !p_material->shader->spatial.writes_modelview_or_projection && !p_material->shader->spatial.uses_vertex && !p_material->shader->spatial.uses_discard && p_material->shader->spatial.depth_draw_mode != RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) {

View file

@ -191,6 +191,14 @@ Error AudioDriverPulseAudio::init_device() {
spec.format = PA_SAMPLE_S16LE; spec.format = PA_SAMPLE_S16LE;
spec.channels = pa_map.channels; spec.channels = pa_map.channels;
spec.rate = mix_rate; spec.rate = mix_rate;
pa_map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
pa_map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
pa_map.map[2] = PA_CHANNEL_POSITION_FRONT_CENTER;
pa_map.map[3] = PA_CHANNEL_POSITION_LFE;
pa_map.map[4] = PA_CHANNEL_POSITION_REAR_LEFT;
pa_map.map[5] = PA_CHANNEL_POSITION_REAR_RIGHT;
pa_map.map[6] = PA_CHANNEL_POSITION_SIDE_LEFT;
pa_map.map[7] = PA_CHANNEL_POSITION_SIDE_RIGHT;
pa_str = pa_stream_new(pa_ctx, "Sound", &spec, &pa_map); pa_str = pa_stream_new(pa_ctx, "Sound", &spec, &pa_map);
if (pa_str == NULL) { if (pa_str == NULL) {

View file

@ -544,7 +544,7 @@ public:
if (use_fps && animation->get_step() > 0) { if (use_fps && animation->get_step() > 0) {
float max_frame = animation->get_length() / animation->get_step(); float max_frame = animation->get_length() / animation->get_step();
p_list->push_back(PropertyInfo(Variant::REAL, "frame", PROPERTY_HINT_RANGE, "0," + rtos(max_frame) + ",0.01")); p_list->push_back(PropertyInfo(Variant::REAL, "frame", PROPERTY_HINT_RANGE, "0," + rtos(max_frame) + ",1"));
} else { } else {
p_list->push_back(PropertyInfo(Variant::REAL, "time", PROPERTY_HINT_RANGE, "0," + rtos(animation->get_length()) + ",0.01")); p_list->push_back(PropertyInfo(Variant::REAL, "time", PROPERTY_HINT_RANGE, "0," + rtos(animation->get_length()) + ",0.01"));
} }
@ -1205,7 +1205,9 @@ AnimationTimelineEdit::AnimationTimelineEdit() {
//////////////////////////////////// ////////////////////////////////////
void AnimationTrackEdit::_notification(int p_what) { void AnimationTrackEdit::_notification(int p_what) {
if (p_what == NOTIFICATION_DRAW) { if (p_what == NOTIFICATION_DRAW) {
if (animation.is_null()) if (animation.is_null())
return; return;
ERR_FAIL_INDEX(track, animation->get_track_count()); ERR_FAIL_INDEX(track, animation->get_track_count());
@ -1241,20 +1243,15 @@ void AnimationTrackEdit::_notification(int p_what) {
int ofs = in_group ? check->get_width() : 0; //not the best reference for margin but.. int ofs = in_group ? check->get_width() : 0; //not the best reference for margin but..
check_rect = Rect2(Point2(ofs, int(get_size().height - check->get_height()) / 2), check->get_size()); check_rect = Rect2(Point2(ofs, int(get_size().height - check->get_height()) / 2), check->get_size());
draw_texture(check, check_rect.position); draw_texture(check, check_rect.position);
ofs += check->get_width() + hsep; ofs += check->get_width() + hsep;
Ref<Texture> type_icon = type_icons[animation->track_get_type(track)]; Ref<Texture> type_icon = type_icons[animation->track_get_type(track)];
draw_texture(type_icon, Point2(ofs, int(get_size().height - type_icon->get_height()) / 2)); draw_texture(type_icon, Point2(ofs, int(get_size().height - type_icon->get_height()) / 2));
ofs += type_icon->get_width() + hsep; ofs += type_icon->get_width() + hsep;
NodePath path = animation->track_get_path(track); NodePath path = animation->track_get_path(track);
Node *node = NULL; Node *node = NULL;
if (root && root->has_node(path)) { if (root && root->has_node(path)) {
node = root->get_node(path); node = root->get_node(path);
} }
@ -1319,12 +1316,11 @@ void AnimationTrackEdit::_notification(int p_what) {
draw_line(Point2(limit, 0), Point2(limit, get_size().height), linecolor, Math::round(EDSCALE)); draw_line(Point2(limit, 0), Point2(limit, get_size().height), linecolor, Math::round(EDSCALE));
} }
// KEYFAMES // // KEYFRAMES //
draw_bg(limit, get_size().width - timeline->get_buttons_width()); draw_bg(limit, get_size().width - timeline->get_buttons_width());
{ {
float scale = timeline->get_zoom_scale(); float scale = timeline->get_zoom_scale();
int limit_end = get_size().width - timeline->get_buttons_width(); int limit_end = get_size().width - timeline->get_buttons_width();
@ -1353,6 +1349,7 @@ void AnimationTrackEdit::_notification(int p_what) {
draw_fg(limit, get_size().width - timeline->get_buttons_width()); draw_fg(limit, get_size().width - timeline->get_buttons_width());
// BUTTONS // // BUTTONS //
{ {
Ref<Texture> wrap_icon[2] = { Ref<Texture> wrap_icon[2] = {
@ -1577,7 +1574,18 @@ void AnimationTrackEdit::draw_key(int p_index, float p_pixels_sec, int p_x, bool
if (p_x < p_clip_left || p_x > p_clip_right) if (p_x < p_clip_left || p_x > p_clip_right)
return; return;
Vector2 ofs(p_x - type_icon->get_width() / 2, int(get_size().height - type_icon->get_height()) / 2); Ref<Texture> icon_to_draw = p_selected ? selected_icon : type_icon;
// Override type icon for invalid value keys, unless selected.
if (!p_selected && animation->track_get_type(track) == Animation::TYPE_VALUE) {
const Variant &v = animation->track_get_key_value(track, p_index);
Variant::Type valid_type = Variant::NIL;
if (!_is_value_key_valid(v, valid_type)) {
icon_to_draw = get_icon("KeyInvalid", "EditorIcons");
}
}
Vector2 ofs(p_x - icon_to_draw->get_width() / 2, int(get_size().height - icon_to_draw->get_height()) / 2);
if (animation->track_get_type(track) == Animation::TYPE_METHOD) { if (animation->track_get_type(track) == Animation::TYPE_METHOD) {
Ref<Font> font = get_font("font", "Label"); Ref<Font> font = get_font("font", "Label");
@ -1601,16 +1609,13 @@ void AnimationTrackEdit::draw_key(int p_index, float p_pixels_sec, int p_x, bool
} }
text += ")"; text += ")";
int limit = MAX(0, p_clip_right - p_x - type_icon->get_width()); int limit = MAX(0, p_clip_right - p_x - icon_to_draw->get_width());
if (limit > 0) { if (limit > 0) {
draw_string(font, Vector2(p_x + type_icon->get_width(), int(get_size().height - font->get_height()) / 2 + font->get_ascent()), text, color, limit); draw_string(font, Vector2(p_x + icon_to_draw->get_width(), int(get_size().height - font->get_height()) / 2 + font->get_ascent()), text, color, limit);
} }
} }
if (p_selected) {
draw_texture(selected_icon, ofs); draw_texture(icon_to_draw, ofs);
} else {
draw_texture(type_icon, ofs);
}
} }
//helper //helper
@ -1775,6 +1780,27 @@ void AnimationTrackEdit::_path_entered(const String &p_text) {
undo_redo->commit_action(); undo_redo->commit_action();
} }
bool AnimationTrackEdit::_is_value_key_valid(const Variant &p_key_value, Variant::Type &r_valid_type) const {
RES res;
Vector<StringName> leftover_path;
Node *node = root->get_node_and_resource(animation->track_get_path(track), res, leftover_path);
Object *obj = NULL;
if (res.is_valid()) {
obj = res.ptr();
} else if (node) {
obj = node;
}
bool prop_exists = false;
if (obj) {
r_valid_type = obj->get_static_property_type_indexed(leftover_path, &prop_exists);
}
return (!prop_exists || Variant::can_convert(p_key_value.get_type(), r_valid_type));
}
String AnimationTrackEdit::get_tooltip(const Point2 &p_pos) const { String AnimationTrackEdit::get_tooltip(const Point2 &p_pos) const {
if (check_rect.has_point(p_pos)) { if (check_rect.has_point(p_pos)) {
@ -1845,29 +1871,10 @@ String AnimationTrackEdit::get_tooltip(const Point2 &p_pos) const {
} break; } break;
case Animation::TYPE_VALUE: { case Animation::TYPE_VALUE: {
Variant v = animation->track_get_key_value(track, key_idx); const Variant &v = animation->track_get_key_value(track, key_idx);
//text+="value: "+String(v)+"\n";
bool prop_exists = false;
Variant::Type valid_type = Variant::NIL;
Object *obj = NULL;
RES res;
Vector<StringName> leftover_path;
Node *node = root->get_node_and_resource(animation->track_get_path(track), res, leftover_path);
if (res.is_valid()) {
obj = res.ptr();
} else if (node) {
obj = node;
}
if (obj) {
valid_type = obj->get_static_property_type_indexed(leftover_path, &prop_exists);
}
text += "Type: " + Variant::get_type_name(v.get_type()) + "\n"; text += "Type: " + Variant::get_type_name(v.get_type()) + "\n";
if (prop_exists && !Variant::can_convert(v.get_type(), valid_type)) { Variant::Type valid_type = Variant::NIL;
if (!_is_value_key_valid(v, valid_type)) {
text += "Value: " + String(v) + " (Invalid, expected type: " + Variant::get_type_name(valid_type) + ")\n"; text += "Value: " + String(v) + " (Invalid, expected type: " + Variant::get_type_name(valid_type) + ")\n";
} else { } else {
text += "Value: " + String(v) + "\n"; text += "Value: " + String(v) + "\n";
@ -4122,6 +4129,7 @@ void AnimationTrackEditor::_update_key_edit() {
key_edit = memnew(AnimationTrackKeyEdit); key_edit = memnew(AnimationTrackKeyEdit);
key_edit->animation = animation; key_edit->animation = animation;
key_edit->track = selection.front()->key().track; key_edit->track = selection.front()->key().track;
key_edit->use_fps = timeline->is_using_fps();
float ofs = animation->track_get_key_time(key_edit->track, selection.front()->key().key); float ofs = animation->track_get_key_time(key_edit->track, selection.front()->key().key);
key_edit->key_ofs = ofs; key_edit->key_ofs = ofs;

View file

@ -31,6 +31,11 @@
#ifndef ANIMATION_TRACK_EDITOR_H #ifndef ANIMATION_TRACK_EDITOR_H
#define ANIMATION_TRACK_EDITOR_H #define ANIMATION_TRACK_EDITOR_H
#include "editor/editor_data.h"
#include "editor/editor_spin_slider.h"
#include "editor/property_editor.h"
#include "editor/property_selector.h"
#include "scene/animation/animation_cache.h"
#include "scene/gui/control.h" #include "scene/gui/control.h"
#include "scene/gui/file_dialog.h" #include "scene/gui/file_dialog.h"
#include "scene/gui/menu_button.h" #include "scene/gui/menu_button.h"
@ -40,12 +45,6 @@
#include "scene/gui/tab_container.h" #include "scene/gui/tab_container.h"
#include "scene/gui/texture_rect.h" #include "scene/gui/texture_rect.h"
#include "scene/gui/tool_button.h" #include "scene/gui/tool_button.h"
#include "editor/property_selector.h"
#include "editor_data.h"
#include "editor_spin_slider.h"
#include "property_editor.h"
#include "scene/animation/animation_cache.h"
#include "scene/resources/animation.h" #include "scene/resources/animation.h"
#include "scene_tree_editor.h" #include "scene_tree_editor.h"
@ -175,8 +174,9 @@ class AnimationTrackEdit : public Control {
void _path_entered(const String &p_text); void _path_entered(const String &p_text);
void _play_position_draw(); void _play_position_draw();
mutable int dropping_at; bool _is_value_key_valid(const Variant &p_key_value, Variant::Type &r_valid_type) const;
mutable int dropping_at;
float insert_at_pos; float insert_at_pos;
bool moving_selection_attempt; bool moving_selection_attempt;
int select_single_attempt; int select_single_attempt;

View file

@ -772,7 +772,7 @@ EditorAutoloadSettings::EditorAutoloadSettings() {
} }
} }
if (!info.is_singleton && !info.in_editor) { if (!info.is_singleton && !info.in_editor && info.node != NULL) {
memdelete(info.node); memdelete(info.node);
info.node = NULL; info.node = NULL;
} }

View file

@ -560,6 +560,7 @@ void EditorData::move_edited_scene_index(int p_idx, int p_to_idx) {
ERR_FAIL_INDEX(p_to_idx, edited_scene.size()); ERR_FAIL_INDEX(p_to_idx, edited_scene.size());
SWAP(edited_scene.write[p_idx], edited_scene.write[p_to_idx]); SWAP(edited_scene.write[p_idx], edited_scene.write[p_to_idx]);
} }
void EditorData::remove_scene(int p_idx) { void EditorData::remove_scene(int p_idx) {
ERR_FAIL_INDEX(p_idx, edited_scene.size()); ERR_FAIL_INDEX(p_idx, edited_scene.size());
if (edited_scene[p_idx].root) { if (edited_scene[p_idx].root) {

View file

@ -611,6 +611,7 @@ void EditorExportPlugin::_bind_methods() {
BIND_VMETHOD(MethodInfo("_export_file", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "type"), PropertyInfo(Variant::POOL_STRING_ARRAY, "features"))); BIND_VMETHOD(MethodInfo("_export_file", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "type"), PropertyInfo(Variant::POOL_STRING_ARRAY, "features")));
BIND_VMETHOD(MethodInfo("_export_begin", PropertyInfo(Variant::POOL_STRING_ARRAY, "features"), PropertyInfo(Variant::BOOL, "is_debug"), PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::INT, "flags"))); BIND_VMETHOD(MethodInfo("_export_begin", PropertyInfo(Variant::POOL_STRING_ARRAY, "features"), PropertyInfo(Variant::BOOL, "is_debug"), PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::INT, "flags")));
BIND_VMETHOD(MethodInfo("_export_end"));
} }
EditorExportPlugin::EditorExportPlugin() { EditorExportPlugin::EditorExportPlugin() {

View file

@ -175,8 +175,9 @@ String EditorHelp::_fix_constant(const String &p_constant) const {
if (p_constant.strip_edges() == "2147483647") { if (p_constant.strip_edges() == "2147483647") {
return "0x7FFFFFFF"; return "0x7FFFFFFF";
} }
if (p_constant.strip_edges() == "1048575") { if (p_constant.strip_edges() == "1048575") {
return "0xfffff"; return "0xFFFFF";
} }
return p_constant; return p_constant;

View file

@ -504,6 +504,7 @@ void EditorNode::_fs_changed() {
void EditorNode::_resources_reimported(const Vector<String> &p_resources) { void EditorNode::_resources_reimported(const Vector<String> &p_resources) {
List<String> scenes; //will load later List<String> scenes; //will load later
int current_tab = scene_tabs->get_current_tab();
for (int i = 0; i < p_resources.size(); i++) { for (int i = 0; i < p_resources.size(); i++) {
String file_type = ResourceLoader::get_resource_type(p_resources[i]); String file_type = ResourceLoader::get_resource_type(p_resources[i]);
@ -526,6 +527,8 @@ void EditorNode::_resources_reimported(const Vector<String> &p_resources) {
for (List<String>::Element *E = scenes.front(); E; E = E->next()) { for (List<String>::Element *E = scenes.front(); E; E = E->next()) {
reload_scene(E->get()); reload_scene(E->get());
} }
scene_tabs->set_current_tab(current_tab);
} }
void EditorNode::_sources_changed(bool p_exist) { void EditorNode::_sources_changed(bool p_exist) {
@ -1189,6 +1192,17 @@ void EditorNode::save_all_scenes() {
_save_all_scenes(); _save_all_scenes();
} }
void EditorNode::save_scene_list(Vector<String> p_scene_filenames) {
for (int i = 0; i < editor_data.get_edited_scene_count(); i++) {
Node *scene = editor_data.get_edited_scene_root(i);
if (scene && (p_scene_filenames.find(scene->get_filename()) >= 0)) {
_save_scene(scene->get_filename(), i);
}
}
}
void EditorNode::restart_editor() { void EditorNode::restart_editor() {
exiting = true; exiting = true;
@ -2744,7 +2758,7 @@ bool EditorNode::is_addon_plugin_enabled(const String &p_addon) const {
return plugin_addons.has(p_addon); return plugin_addons.has(p_addon);
} }
void EditorNode::_remove_edited_scene() { void EditorNode::_remove_edited_scene(bool p_change_tab) {
int new_index = editor_data.get_edited_scene(); int new_index = editor_data.get_edited_scene();
int old_index = new_index; int old_index = new_index;
@ -2760,18 +2774,19 @@ void EditorNode::_remove_edited_scene() {
if (editor_data.get_scene_path(old_index) != String()) { if (editor_data.get_scene_path(old_index) != String()) {
ScriptEditor::get_singleton()->close_builtin_scripts_from_scene(editor_data.get_scene_path(old_index)); ScriptEditor::get_singleton()->close_builtin_scripts_from_scene(editor_data.get_scene_path(old_index));
} }
_scene_tab_changed(new_index);
if (p_change_tab) _scene_tab_changed(new_index);
editor_data.remove_scene(old_index); editor_data.remove_scene(old_index);
editor_data.get_undo_redo().clear_history(false); editor_data.get_undo_redo().clear_history(false);
_update_title(); _update_title();
_update_scene_tabs(); _update_scene_tabs();
} }
void EditorNode::_remove_scene(int index) { void EditorNode::_remove_scene(int index, bool p_change_tab) {
if (editor_data.get_edited_scene() == index) { if (editor_data.get_edited_scene() == index) {
//Scene to remove is current scene //Scene to remove is current scene
_remove_edited_scene(); _remove_edited_scene(p_change_tab);
} else { } else {
//Scene to remove is not active scene //Scene to remove is not active scene
editor_data.remove_scene(index); editor_data.remove_scene(index);
@ -4023,6 +4038,14 @@ bool EditorNode::has_scenes_in_session() {
return !scenes.empty(); return !scenes.empty();
} }
int EditorNode::get_current_tab() {
return scene_tabs->get_current_tab();
}
void EditorNode::set_current_tab(int p_tab) {
scene_tabs->set_current_tab(p_tab);
}
void EditorNode::_update_layouts_menu() { void EditorNode::_update_layouts_menu() {
editor_layouts->clear(); editor_layouts->clear();
@ -4612,8 +4635,7 @@ void EditorNode::reload_scene(const String &p_path) {
if (scene_idx == -1) { if (scene_idx == -1) {
if (get_edited_scene()) { if (get_edited_scene()) {
//scene is not open, so at it might be instanced, just refresh, set tab to itself and it will reload //scene is not open, so at it might be instanced. We'll refresh the whole scene later.
set_current_scene(current_tab);
editor_data.get_undo_redo().clear_history(); editor_data.get_undo_redo().clear_history();
} }
return; return;
@ -4623,17 +4645,19 @@ void EditorNode::reload_scene(const String &p_path) {
editor_data.apply_changes_in_editors(); editor_data.apply_changes_in_editors();
_set_scene_metadata(p_path); _set_scene_metadata(p_path);
} }
//remove scene
_remove_scene(scene_idx);
//reload scene
//remove scene
_remove_scene(scene_idx, false);
//reload scene
load_scene(p_path, true, false, true, true); load_scene(p_path, true, false, true, true);
//adjust index so tab is back a the previous position //adjust index so tab is back a the previous position
editor_data.move_edited_scene_to_index(scene_idx); editor_data.move_edited_scene_to_index(scene_idx);
get_undo_redo()->clear_history(); get_undo_redo()->clear_history();
//recover the tab //recover the tab
scene_tabs->set_current_tab(current_tab); scene_tabs->set_current_tab(current_tab);
_scene_tab_changed(current_tab);
} }
int EditorNode::plugin_init_callback_count = 0; int EditorNode::plugin_init_callback_count = 0;
@ -5440,7 +5464,7 @@ EditorNode::EditorNode() {
p->add_shortcut(ED_SHORTCUT("editor/undo", TTR("Undo"), KEY_MASK_CMD + KEY_Z), EDIT_UNDO, true); p->add_shortcut(ED_SHORTCUT("editor/undo", TTR("Undo"), KEY_MASK_CMD + KEY_Z), EDIT_UNDO, true);
p->add_shortcut(ED_SHORTCUT("editor/redo", TTR("Redo"), KEY_MASK_SHIFT + KEY_MASK_CMD + KEY_Z), EDIT_REDO, true); p->add_shortcut(ED_SHORTCUT("editor/redo", TTR("Redo"), KEY_MASK_SHIFT + KEY_MASK_CMD + KEY_Z), EDIT_REDO, true);
p->add_separator(); p->add_separator();
p->add_item(TTR("Revert Scene"), EDIT_REVERT); p->add_shortcut(ED_SHORTCUT("editor/revert_scene", TTR("Revert Scene")), EDIT_REVERT);
recent_scenes = memnew(PopupMenu); recent_scenes = memnew(PopupMenu);
recent_scenes->set_name("RecentScenes"); recent_scenes->set_name("RecentScenes");
@ -5460,10 +5484,10 @@ EditorNode::EditorNode() {
p = project_menu->get_popup(); p = project_menu->get_popup();
p->set_hide_on_window_lose_focus(true); p->set_hide_on_window_lose_focus(true);
p->add_item(TTR("Project Settings"), RUN_SETTINGS); p->add_shortcut(ED_SHORTCUT("editor/project_settings", TTR("Project Settings")), RUN_SETTINGS);
p->add_separator(); p->add_separator();
p->connect("id_pressed", this, "_menu_option"); p->connect("id_pressed", this, "_menu_option");
p->add_item(TTR("Export"), FILE_EXPORT_PROJECT); p->add_shortcut(ED_SHORTCUT("editor/export", TTR("Export")), FILE_EXPORT_PROJECT);
plugin_config_dialog = memnew(PluginConfigDialog); plugin_config_dialog = memnew(PluginConfigDialog);
plugin_config_dialog->connect("plugin_ready", this, "_on_plugin_ready"); plugin_config_dialog->connect("plugin_ready", this, "_on_plugin_ready");
@ -5474,10 +5498,10 @@ EditorNode::EditorNode() {
tool_menu->connect("index_pressed", this, "_tool_menu_option"); tool_menu->connect("index_pressed", this, "_tool_menu_option");
p->add_child(tool_menu); p->add_child(tool_menu);
p->add_submenu_item(TTR("Tools"), "Tools"); p->add_submenu_item(TTR("Tools"), "Tools");
tool_menu->add_item(TTR("Orphan Resource Explorer"), TOOLS_ORPHAN_RESOURCES); tool_menu->add_shortcut(ED_SHORTCUT("editor/orphan_resource_explorer", TTR("Orphan Resource Explorer")), TOOLS_ORPHAN_RESOURCES);
p->add_separator(); p->add_separator();
p->add_item(TTR("Open Project Data Folder"), RUN_PROJECT_DATA_FOLDER); p->add_shortcut(ED_SHORTCUT("editor/open_project_data_folder", TTR("Open Project Data Folder")), RUN_PROJECT_DATA_FOLDER);
p->add_separator(); p->add_separator();
#ifdef OSX_ENABLED #ifdef OSX_ENABLED
@ -5501,21 +5525,21 @@ EditorNode::EditorNode() {
p = debug_menu->get_popup(); p = debug_menu->get_popup();
p->set_hide_on_window_lose_focus(true); p->set_hide_on_window_lose_focus(true);
p->set_hide_on_item_selection(false); p->set_hide_on_item_selection(false);
p->add_check_item(TTR("Deploy with Remote Debug"), RUN_DEPLOY_REMOTE_DEBUG); p->add_check_shortcut(ED_SHORTCUT("editor/deploy_with_remote_debug", TTR("Deploy with Remote Debug")), RUN_DEPLOY_REMOTE_DEBUG);
p->set_item_tooltip(p->get_item_count() - 1, TTR("When exporting or deploying, the resulting executable will attempt to connect to the IP of this computer in order to be debugged.")); p->set_item_tooltip(p->get_item_count() - 1, TTR("When exporting or deploying, the resulting executable will attempt to connect to the IP of this computer in order to be debugged."));
p->add_check_item(TTR("Small Deploy with Network FS"), RUN_FILE_SERVER); p->add_check_shortcut(ED_SHORTCUT("editor/small_deploy_with_network_fs", TTR("Small Deploy with Network FS")), RUN_FILE_SERVER);
p->set_item_tooltip(p->get_item_count() - 1, TTR("When this option is enabled, export or deploy will produce a minimal executable.\nThe filesystem will be provided from the project by the editor over the network.\nOn Android, deploy will use the USB cable for faster performance. This option speeds up testing for games with a large footprint.")); p->set_item_tooltip(p->get_item_count() - 1, TTR("When this option is enabled, export or deploy will produce a minimal executable.\nThe filesystem will be provided from the project by the editor over the network.\nOn Android, deploy will use the USB cable for faster performance. This option speeds up testing for games with a large footprint."));
p->add_separator(); p->add_separator();
p->add_check_item(TTR("Visible Collision Shapes"), RUN_DEBUG_COLLISONS); p->add_check_shortcut(ED_SHORTCUT("editor/visible_collision_shapes", TTR("Visible Collision Shapes")), RUN_DEBUG_COLLISONS);
p->set_item_tooltip(p->get_item_count() - 1, TTR("Collision shapes and raycast nodes (for 2D and 3D) will be visible on the running game if this option is turned on.")); p->set_item_tooltip(p->get_item_count() - 1, TTR("Collision shapes and raycast nodes (for 2D and 3D) will be visible on the running game if this option is turned on."));
p->add_check_item(TTR("Visible Navigation"), RUN_DEBUG_NAVIGATION); p->add_check_shortcut(ED_SHORTCUT("editor/visible_navigation", TTR("Visible Navigation")), RUN_DEBUG_NAVIGATION);
p->set_item_tooltip(p->get_item_count() - 1, TTR("Navigation meshes and polygons will be visible on the running game if this option is turned on.")); p->set_item_tooltip(p->get_item_count() - 1, TTR("Navigation meshes and polygons will be visible on the running game if this option is turned on."));
p->add_separator(); p->add_separator();
//those are now on by default, since they are harmless //those are now on by default, since they are harmless
p->add_check_item(TTR("Sync Scene Changes"), RUN_LIVE_DEBUG); p->add_check_shortcut(ED_SHORTCUT("editor/sync_scene_changes", TTR("Sync Scene Changes")), RUN_LIVE_DEBUG);
p->set_item_tooltip(p->get_item_count() - 1, TTR("When this option is turned on, any changes made to the scene in the editor will be replicated in the running game.\nWhen used remotely on a device, this is more efficient with network filesystem.")); p->set_item_tooltip(p->get_item_count() - 1, TTR("When this option is turned on, any changes made to the scene in the editor will be replicated in the running game.\nWhen used remotely on a device, this is more efficient with network filesystem."));
p->set_item_checked(p->get_item_count() - 1, true); p->set_item_checked(p->get_item_count() - 1, true);
p->add_check_item(TTR("Sync Script Changes"), RUN_RELOAD_SCRIPTS); p->add_check_shortcut(ED_SHORTCUT("editor/sync_script_changes", TTR("Sync Script Changes")), RUN_RELOAD_SCRIPTS);
p->set_item_tooltip(p->get_item_count() - 1, TTR("When this option is turned on, any script that is saved will be reloaded on the running game.\nWhen used remotely on a device, this is more efficient with network filesystem.")); p->set_item_tooltip(p->get_item_count() - 1, TTR("When this option is turned on, any script that is saved will be reloaded on the running game.\nWhen used remotely on a device, this is more efficient with network filesystem."));
p->set_item_checked(p->get_item_count() - 1, true); p->set_item_checked(p->get_item_count() - 1, true);
p->connect("id_pressed", this, "_menu_option"); p->connect("id_pressed", this, "_menu_option");
@ -5531,7 +5555,7 @@ EditorNode::EditorNode() {
p = settings_menu->get_popup(); p = settings_menu->get_popup();
p->set_hide_on_window_lose_focus(true); p->set_hide_on_window_lose_focus(true);
p->add_item(TTR("Editor Settings"), SETTINGS_PREFERENCES); p->add_shortcut(ED_SHORTCUT("editor/editor_settings", TTR("Editor Settings")), SETTINGS_PREFERENCES);
p->add_separator(); p->add_separator();
editor_layouts = memnew(PopupMenu); editor_layouts = memnew(PopupMenu);
@ -5571,12 +5595,12 @@ EditorNode::EditorNode() {
p->connect("id_pressed", this, "_menu_option"); p->connect("id_pressed", this, "_menu_option");
p->add_icon_shortcut(gui_base->get_icon("HelpSearch", "EditorIcons"), ED_SHORTCUT("editor/editor_help", TTR("Search"), KEY_F4), HELP_SEARCH); p->add_icon_shortcut(gui_base->get_icon("HelpSearch", "EditorIcons"), ED_SHORTCUT("editor/editor_help", TTR("Search"), KEY_F4), HELP_SEARCH);
p->add_separator(); p->add_separator();
p->add_icon_item(gui_base->get_icon("Instance", "EditorIcons"), TTR("Online Docs"), HELP_DOCS); p->add_icon_shortcut(gui_base->get_icon("Instance", "EditorIcons"), ED_SHORTCUT("editor/online_docs", TTR("Online Docs")), HELP_DOCS);
p->add_icon_item(gui_base->get_icon("Instance", "EditorIcons"), TTR("Q&A"), HELP_QA); p->add_icon_shortcut(gui_base->get_icon("Instance", "EditorIcons"), ED_SHORTCUT("editor/q&a", TTR("Q&A")), HELP_QA);
p->add_icon_item(gui_base->get_icon("Instance", "EditorIcons"), TTR("Issue Tracker"), HELP_ISSUES); p->add_icon_shortcut(gui_base->get_icon("Instance", "EditorIcons"), ED_SHORTCUT("editor/issue_tracker", TTR("Issue Tracker")), HELP_ISSUES);
p->add_icon_item(gui_base->get_icon("Instance", "EditorIcons"), TTR("Community"), HELP_COMMUNITY); p->add_icon_shortcut(gui_base->get_icon("Instance", "EditorIcons"), ED_SHORTCUT("editor/community", TTR("Community")), HELP_COMMUNITY);
p->add_separator(); p->add_separator();
p->add_icon_item(gui_base->get_icon("Godot", "EditorIcons"), TTR("About"), HELP_ABOUT); p->add_icon_shortcut(gui_base->get_icon("Godot", "EditorIcons"), ED_SHORTCUT("editor/about", TTR("About")), HELP_ABOUT);
HBoxContainer *play_hb = memnew(HBoxContainer); HBoxContainer *play_hb = memnew(HBoxContainer);
menu_hb->add_child(play_hb); menu_hb->add_child(play_hb);

View file

@ -499,8 +499,8 @@ private:
static void _editor_file_dialog_unregister(EditorFileDialog *p_dialog); static void _editor_file_dialog_unregister(EditorFileDialog *p_dialog);
void _cleanup_scene(); void _cleanup_scene();
void _remove_edited_scene(); void _remove_edited_scene(bool p_change_tab = true);
void _remove_scene(int index); void _remove_scene(int index, bool p_change_tab = true);
bool _find_and_save_resource(RES p_res, Map<RES, bool> &processed, int32_t flags); bool _find_and_save_resource(RES p_res, Map<RES, bool> &processed, int32_t flags);
bool _find_and_save_edited_subresources(Object *obj, Map<RES, bool> &processed, int32_t flags); bool _find_and_save_edited_subresources(Object *obj, Map<RES, bool> &processed, int32_t flags);
void _save_edited_subresources(Node *scene, Map<RES, bool> &processed, int32_t flags); void _save_edited_subresources(Node *scene, Map<RES, bool> &processed, int32_t flags);
@ -615,6 +615,12 @@ protected:
void _notification(int p_what); void _notification(int p_what);
static void _bind_methods(); static void _bind_methods();
protected:
friend class FileSystemDock;
int get_current_tab();
void set_current_tab(int p_tab);
public: public:
bool call_build(); bool call_build();
@ -786,6 +792,7 @@ public:
void remove_tool_menu_item(const String &p_name); void remove_tool_menu_item(const String &p_name);
void save_all_scenes(); void save_all_scenes();
void save_scene_list(Vector<String> p_scene_filenames);
void restart_editor(); void restart_editor();
void dim_editor(bool p_dimming); void dim_editor(bool p_dimming);

View file

@ -2289,6 +2289,16 @@ void EditorPropertyResource::_update_menu_items() {
E = E->next(); E = E->next();
} }
List<StringName> global_classes;
ScriptServer::get_global_class_list(&global_classes);
E = global_classes.front();
while (E) {
if (EditorNode::get_editor_data().script_class_is_parent(E->get(), base_type)) {
valid_inheritors.insert(E->get());
}
E = E->next();
}
for (Set<String>::Element *F = valid_inheritors.front(); F; F = F->next()) { for (Set<String>::Element *F = valid_inheritors.front(); F; F = F->next()) {
String t = F->get(); String t = F->get();
@ -2305,7 +2315,7 @@ void EditorPropertyResource::_update_menu_items() {
} }
} }
if (!is_custom_resource && !ClassDB::can_instance(t)) if (!is_custom_resource && !(ScriptServer::is_global_class(t) || ClassDB::can_instance(t)))
continue; continue;
inheritors_array.push_back(t); inheritors_array.push_back(t);

View file

@ -268,6 +268,11 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
String host_lang = OS::get_singleton()->get_locale(); String host_lang = OS::get_singleton()->get_locale();
host_lang = TranslationServer::standardize_locale(host_lang); host_lang = TranslationServer::standardize_locale(host_lang);
// Some locales are not properly supported currently in Godot due to lack of font shaping
// (e.g. Arabic or Hindi), so even though we have work in progress translations for them,
// we skip them as they don't render properly. (GH-28577)
const Vector<String> locales_to_skip = String("ar,bn,fa,he,hi,ml,si,ta,te,ur").split(",");
String best; String best;
EditorTranslationList *etl = _editor_translations; EditorTranslationList *etl = _editor_translations;
@ -275,6 +280,15 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
while (etl->data) { while (etl->data) {
const String &locale = etl->lang; const String &locale = etl->lang;
// Skip locales which we can't render properly (see above comment).
// Test against language code without regional variants (e.g. ur_PK).
String lang_code = locale.get_slice("_", 0);
if (locales_to_skip.find(lang_code) != -1) {
etl++;
continue;
}
lang_hint += ","; lang_hint += ",";
lang_hint += locale; lang_hint += locale;
@ -543,6 +557,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
_initial_set("editors/2d/bone_outline_size", 2); _initial_set("editors/2d/bone_outline_size", 2);
_initial_set("editors/2d/keep_margins_when_changing_anchors", false); _initial_set("editors/2d/keep_margins_when_changing_anchors", false);
_initial_set("editors/2d/viewport_border_color", Color(0.4, 0.4, 1.0, 0.4)); _initial_set("editors/2d/viewport_border_color", Color(0.4, 0.4, 1.0, 0.4));
_initial_set("editors/2d/constrain_editor_view", true);
_initial_set("editors/2d/warped_mouse_panning", true); _initial_set("editors/2d/warped_mouse_panning", true);
_initial_set("editors/2d/simple_spacebar_panning", false); _initial_set("editors/2d/simple_spacebar_panning", false);
_initial_set("editors/2d/scroll_to_pan", false); _initial_set("editors/2d/scroll_to_pan", false);

View file

@ -1167,6 +1167,21 @@ void FileSystemDock::_update_favorites_list_after_move(const Map<String, String>
EditorSettings::get_singleton()->set_favorites(new_favorites); EditorSettings::get_singleton()->set_favorites(new_favorites);
} }
void FileSystemDock::_save_scenes_after_move(const Map<String, String> &p_renames) const {
Vector<String> remaps;
_find_remaps(EditorFileSystem::get_singleton()->get_filesystem(), p_renames, remaps);
Vector<String> new_filenames;
for (int i = 0; i < remaps.size(); ++i) {
String file = p_renames.has(remaps[i]) ? p_renames[remaps[i]] : remaps[i];
if (ResourceLoader::get_resource_type(file) == "PackedScene") {
new_filenames.push_back(file);
}
}
editor->save_scene_list(new_filenames);
}
void FileSystemDock::_make_dir_confirm() { void FileSystemDock::_make_dir_confirm() {
String dir_name = make_dir_dialog_text->get_text().strip_edges(); String dir_name = make_dir_dialog_text->get_text().strip_edges();
@ -1241,14 +1256,21 @@ void FileSystemDock::_rename_operation_confirm() {
Map<String, String> file_renames; Map<String, String> file_renames;
Map<String, String> folder_renames; Map<String, String> folder_renames;
_try_move_item(to_rename, new_path, file_renames, folder_renames); _try_move_item(to_rename, new_path, file_renames, folder_renames);
int current_tab = editor->get_current_tab();
_update_dependencies_after_move(file_renames); _update_dependencies_after_move(file_renames);
_update_resource_paths_after_move(file_renames); _update_resource_paths_after_move(file_renames);
_update_project_settings_after_move(file_renames); _update_project_settings_after_move(file_renames);
_update_favorites_list_after_move(file_renames, folder_renames); _update_favorites_list_after_move(file_renames, folder_renames);
//Rescan everything editor->set_current_tab(current_tab);
print_verbose("FileSystem: calling rescan."); print_verbose("FileSystem: calling rescan.");
_rescan(); _rescan();
print_verbose("FileSystem: saving moved scenes.");
_save_scenes_after_move(file_renames);
} }
void FileSystemDock::_duplicate_operation_confirm() { void FileSystemDock::_duplicate_operation_confirm() {
@ -1334,13 +1356,20 @@ void FileSystemDock::_move_operation_confirm(const String &p_to_path, bool overw
} }
if (is_moved) { if (is_moved) {
int current_tab = editor->get_current_tab();
_update_dependencies_after_move(file_renames); _update_dependencies_after_move(file_renames);
_update_resource_paths_after_move(file_renames); _update_resource_paths_after_move(file_renames);
_update_project_settings_after_move(file_renames); _update_project_settings_after_move(file_renames);
_update_favorites_list_after_move(file_renames, folder_renames); _update_favorites_list_after_move(file_renames, folder_renames);
editor->set_current_tab(current_tab);
print_verbose("FileSystem: calling rescan."); print_verbose("FileSystem: calling rescan.");
_rescan(); _rescan();
print_verbose("FileSystem: saving moved scenes.");
_save_scenes_after_move(file_renames);
} }
} }

View file

@ -201,6 +201,7 @@ private:
void _try_duplicate_item(const FileOrFolder &p_item, const String &p_new_path) const; void _try_duplicate_item(const FileOrFolder &p_item, const String &p_new_path) const;
void _update_dependencies_after_move(const Map<String, String> &p_renames) const; void _update_dependencies_after_move(const Map<String, String> &p_renames) const;
void _update_resource_paths_after_move(const Map<String, String> &p_renames) const; void _update_resource_paths_after_move(const Map<String, String> &p_renames) const;
void _save_scenes_after_move(const Map<String, String> &p_renames) const;
void _update_favorites_list_after_move(const Map<String, String> &p_files_renames, const Map<String, String> &p_folders_renames) const; void _update_favorites_list_after_move(const Map<String, String> &p_files_renames, const Map<String, String> &p_folders_renames) const;
void _update_project_settings_after_move(const Map<String, String> &p_folders_renames) const; void _update_project_settings_after_move(const Map<String, String> &p_folders_renames) const;

View file

@ -751,7 +751,6 @@ void FindInFilesPanel::_on_replace_text_changed(String text) {
void FindInFilesPanel::_on_replace_all_clicked() { void FindInFilesPanel::_on_replace_all_clicked() {
String replace_text = get_replace_text(); String replace_text = get_replace_text();
ERR_FAIL_COND(replace_text.empty());
PoolStringArray modified_files; PoolStringArray modified_files;
@ -887,7 +886,7 @@ String FindInFilesPanel::get_replace_text() {
void FindInFilesPanel::update_replace_buttons() { void FindInFilesPanel::update_replace_buttons() {
String text = get_replace_text(); String text = get_replace_text();
bool disabled = text.empty() || _finder->is_searching(); bool disabled = _finder->is_searching();
_replace_all_button->set_disabled(disabled); _replace_all_button->set_disabled(disabled);
} }

View file

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="128"
height="128"
version="1.1"
viewBox="0 0 128 128"
id="svg6"
sodipodi:docname="icon_gizmo_c_p_u_particles.svg"
inkscape:version="0.92.4 5da689c313, 2019-01-14">
<metadata
id="metadata12">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs10" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1606"
inkscape:window-height="821"
id="namedview8"
showgrid="false"
inkscape:zoom="2.6074563"
inkscape:cx="101.29539"
inkscape:cy="83.191634"
inkscape:window-x="295"
inkscape:window-y="81"
inkscape:window-maximized="0"
inkscape:current-layer="svg6"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0" />
<path
style="display:inline;opacity:1;fill:#f7f5cf;fill-opacity:1;stroke:#b4b4b4;stroke-width:2.56380486;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 35.503779,1.2819066 c -3.570424,0 -6.435164,2.9483368 -6.435164,6.6019028 v 4.3900146 c 0,0.889114 0.169457,1.726301 0.478513,2.49893 H 19.465369 c -3.570424,0 -6.435167,2.931453 -6.435167,6.585021 v 7.969562 c -0.341543,-0.0568 -0.648813,-0.202614 -1.006525,-0.202614 H 7.7335674 c -3.5704232,0 -6.451665,2.948338 -6.451665,6.601904 v 3.224972 c 0,3.653568 2.8812418,6.585016 6.451665,6.585016 h 4.2901096 c 0.358169,0 0.664563,-0.14568 1.006525,-0.202618 V 83.83104 C 12.688659,83.77398 12.381388,83.628424 12.023677,83.628424 H 7.7335674 c -3.5704232,0 -6.451665,2.948332 -6.451665,6.601908 v 3.224971 c 0,3.653575 2.8812418,6.585017 6.451665,6.585017 h 4.2901096 c 0.358169,0 0.664563,-0.145692 1.006525,-0.202612 v 9.725542 c 0,3.6536 2.864743,6.60193 6.435167,6.60193 h 9.603246 v 3.951 c 0,3.65357 2.86474,6.60192 6.435164,6.60192 h 3.15158 c 3.57042,0 6.451663,-2.94836 6.451663,-6.60192 v -3.95104 h 37.224955 v 3.951 c 0,3.65358 2.86474,6.60193 6.435166,6.60193 h 3.151583 c 3.570418,0 6.451653,-2.94836 6.451653,-6.60193 v -3.951 h 10.725281 c 3.57043,0 6.45166,-2.94833 6.45166,-6.60191 v -9.607372 c 0.14985,0.0105 0.27643,0.0846 0.42899,0.0846 h 4.29014 c 3.5704,0 6.45165,-2.931432 6.45165,-6.585011 v -3.224992 c 0,-3.653565 -2.88125,-6.601906 -6.45165,-6.601906 h -4.29014 c -0.15231,0 -0.27938,0.07348 -0.42899,0.08472 V 45.452198 c 0.14985,0.01042 0.27643,0.08445 0.42899,0.08445 h 4.29014 c 3.5704,0 6.45165,-2.931451 6.45165,-6.585023 v -3.224986 c 0,-3.653566 -2.88125,-6.601906 -6.45165,-6.601906 h -4.29014 c -0.15231,0 -0.27938,0.07392 -0.42899,0.08446 v -7.851429 c 0,-3.653567 -2.88123,-6.585019 -6.45166,-6.585021 H 97.875379 c 0.309043,-0.772641 0.494982,-1.609791 0.494982,-2.498929 V 7.8838054 c 0,-3.6535651 -2.881246,-6.601903 -6.451662,-6.601903 h -3.15158 c -3.570428,0 -6.435167,2.9483379 -6.435167,6.601903 V 12.27382 c 0,0.889115 0.16948,1.726301 0.478507,2.49893 H 44.612011 c 0.309083,-0.772642 0.495011,-1.609792 0.495011,-2.49893 V 7.8838054 c 0,-3.6535651 -2.881243,-6.601903 -6.451663,-6.601903 z"
id="path4542"
inkscape:connector-curvature="0" />
<path
style="opacity:1;fill:#b4b4b4;fill-opacity:1;stroke-width:8.54601765"
d="M 62.861474,21.661698 A 27.707285,31.502779 0 0 1 90.004671,47.07312 18.471523,18.901669 0 0 1 105.96058,65.764449 18.471523,18.901669 0 0 1 87.480108,84.658396 H 38.226348 A 18.471523,18.901669 0 0 1 19.762375,65.764449 18.471523,18.901669 0 0 1 35.685283,47.056234 27.707285,31.502779 0 0 1 62.861474,21.661698 Z"
id="path4540"
inkscape:connector-curvature="0" />
<path
style="opacity:1;fill:#b4b4b4;fill-opacity:1;stroke-width:8.54601765"
d="m 38.226348,90.956369 a 6.1571744,6.3005562 0 0 1 6.154657,6.297979 6.1571744,6.3005562 0 0 1 -6.154657,6.314882 6.1571744,6.3005562 0 0 1 -6.154657,-6.314882 6.1571744,6.3005562 0 0 1 6.154657,-6.297979 z"
id="path4538"
inkscape:connector-curvature="0" />
<path
style="opacity:1;fill:#b4b4b4;fill-opacity:1;stroke-width:8.54601765"
d="m 87.480108,90.956369 a 6.1571744,6.3005562 0 0 1 6.171159,6.297979 6.1571744,6.3005562 0 0 1 -6.171159,6.314882 6.1571744,6.3005562 0 0 1 -6.154656,-6.314882 6.1571744,6.3005562 0 0 1 6.154656,-6.297979 z"
id="path4536"
inkscape:connector-curvature="0" />
<path
style="opacity:1;fill:#b4b4b4;fill-opacity:1;stroke-width:8.54601765"
d="m 62.861474,97.254348 a 6.1571744,6.3005562 0 0 1 6.154662,6.314882 6.1571744,6.3005562 0 0 1 -6.154662,6.29797 6.1571744,6.3005562 0 0 1 -6.154651,-6.29797 6.1571744,6.3005562 0 0 1 6.154651,-6.314882 z"
id="rect822"
inkscape:connector-curvature="0" />
<g
inkscape:groupmode="layer"
id="layer1"
inkscape:label="Layer 1"
transform="translate(-0.35794507,-5.5049216)" />
</svg>

After

Width:  |  Height:  |  Size: 5.4 KiB

View file

@ -1,5 +0,0 @@
<svg width="8" height="8" version="1.1" viewBox="0 0 8 8" xmlns="http://www.w3.org/2000/svg">
<g transform="translate(0 -1044.4)">
<rect transform="rotate(-45)" x="-741.53" y="741.08" width="6.1027" height="6.1027" ry=".76286" fill="#fff"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 253 B

View file

@ -2087,22 +2087,23 @@ void EditorSceneImporterGLTF::_import_animation(GLTFState &state, AnimationPlaye
animation->add_track(Animation::TYPE_VALUE); animation->add_track(Animation::TYPE_VALUE);
animation->track_set_path(track_idx, node_path); animation->track_set_path(track_idx, node_path);
if (track.weight_tracks[i].interpolation <= GLTFAnimation::INTERP_STEP) { // Only LINEAR and STEP (NEAREST) can be supported out of the box by Godot's Animation,
animation->track_set_interpolation_type(track_idx, track.weight_tracks[i].interpolation == GLTFAnimation::INTERP_STEP ? Animation::INTERPOLATION_NEAREST : Animation::INTERPOLATION_NEAREST); // the other modes have to be baked.
GLTFAnimation::Interpolation gltf_interp = track.weight_tracks[i].interpolation;
if (gltf_interp == GLTFAnimation::INTERP_LINEAR || gltf_interp == GLTFAnimation::INTERP_STEP) {
animation->track_set_interpolation_type(track_idx, gltf_interp == GLTFAnimation::INTERP_STEP ? Animation::INTERPOLATION_NEAREST : Animation::INTERPOLATION_LINEAR);
for (int j = 0; j < track.weight_tracks[i].times.size(); j++) { for (int j = 0; j < track.weight_tracks[i].times.size(); j++) {
float t = track.weight_tracks[i].times[j]; float t = track.weight_tracks[i].times[j];
float w = track.weight_tracks[i].values[j]; float w = track.weight_tracks[i].values[j];
animation->track_insert_key(track_idx, t, w); animation->track_insert_key(track_idx, t, w);
} }
} else { } else {
//must bake, apologies. // CATMULLROMSPLINE or CUBIC_SPLINE have to be baked, apologies.
float increment = 1.0 / float(bake_fps); float increment = 1.0 / float(bake_fps);
float time = 0.0; float time = 0.0;
bool last = false; bool last = false;
while (true) { while (true) {
_interpolate_track<float>(track.weight_tracks[i].times, track.weight_tracks[i].values, time, gltf_interp);
_interpolate_track<float>(track.weight_tracks[i].times, track.weight_tracks[i].values, time, track.weight_tracks[i].interpolation);
if (last) { if (last) {
break; break;
} }

View file

@ -1094,7 +1094,7 @@ void ResourceImporterScene::get_import_options(List<ImportOption> *r_options, in
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/import", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/import", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "animation/fps", PROPERTY_HINT_RANGE, "1,120,1"), 15)); r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "animation/fps", PROPERTY_HINT_RANGE, "1,120,1"), 15));
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "animation/filter_script", PROPERTY_HINT_MULTILINE_TEXT), "")); r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "animation/filter_script", PROPERTY_HINT_MULTILINE_TEXT), ""));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "animation/storage", PROPERTY_HINT_ENUM, "Built-In,Files"), animations_out ? true : false)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "animation/storage", PROPERTY_HINT_ENUM, "Built-In,Files", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), animations_out ? true : false));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/keep_custom_tracks"), animations_out ? true : false)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/keep_custom_tracks"), animations_out ? true : false));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/optimizer/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/optimizer/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "animation/optimizer/max_linear_error"), 0.05)); r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "animation/optimizer/max_linear_error"), 0.05));

View file

@ -1430,6 +1430,7 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() {
new_state["show_rulers"] = false; new_state["show_rulers"] = false;
new_state["show_guides"] = false; new_state["show_guides"] = false;
new_state["show_helpers"] = false; new_state["show_helpers"] = false;
new_state["show_zoom_control"] = false;
// TODO: Save/restore only affected entries // TODO: Save/restore only affected entries
CanvasItemEditor::get_singleton()->set_state(new_state); CanvasItemEditor::get_singleton()->set_state(new_state);
} }
@ -1482,7 +1483,7 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() {
if (valid) { if (valid) {
player->seek(pos, true); player->seek(pos, true);
get_tree()->flush_transform_notifications(); // Needed for transforms of Spatials get_tree()->flush_transform_notifications(); // Needed for transforms of Spatials
values_backup.update_skeletons(); // Needed for Skeletons values_backup.update_skeletons(); // Needed for Skeletons (2D & 3D)
VS::get_singleton()->viewport_set_active(onion.captures[cidx], true); VS::get_singleton()->viewport_set_active(onion.captures[cidx], true);
VS::get_singleton()->viewport_set_parent_viewport(root_vp, onion.captures[cidx]); VS::get_singleton()->viewport_set_parent_viewport(root_vp, onion.captures[cidx]);

View file

@ -726,6 +726,7 @@ void EditorAssetLibrary::_image_update(bool use_cache, bool final, const PoolByt
image_data = cached_data; image_data = cached_data;
file->close(); file->close();
memdelete(file);
} }
} }
@ -800,6 +801,7 @@ void EditorAssetLibrary::_image_request_completed(int p_status, int p_code, cons
if (file) { if (file) {
file->store_line(new_etag); file->store_line(new_etag);
file->close(); file->close();
memdelete(file);
} }
int len = p_data.size(); int len = p_data.size();
@ -809,6 +811,7 @@ void EditorAssetLibrary::_image_request_completed(int p_status, int p_code, cons
file->store_32(len); file->store_32(len);
file->store_buffer(r.ptr(), len); file->store_buffer(r.ptr(), len);
file->close(); file->close();
memdelete(file);
} }
break; break;
@ -848,6 +851,7 @@ void EditorAssetLibrary::_update_image_queue() {
if (file) { if (file) {
headers.push_back("If-None-Match: " + file->get_line()); headers.push_back("If-None-Match: " + file->get_line());
file->close(); file->close();
memdelete(file);
} }
} }

View file

@ -3547,18 +3547,19 @@ void CanvasItemEditor::_update_scrollbars() {
// Constraints the view offset and updates the scrollbars // Constraints the view offset and updates the scrollbars
Point2 begin = canvas_item_rect.position; Point2 begin = canvas_item_rect.position;
Point2 end = canvas_item_rect.position + canvas_item_rect.size - local_rect.size / zoom; Point2 end = canvas_item_rect.position + canvas_item_rect.size - local_rect.size / zoom;
bool constrain_editor_view = bool(EditorSettings::get_singleton()->get("editors/2d/constrain_editor_view"));
if (canvas_item_rect.size.height <= (local_rect.size.y / zoom)) { if (canvas_item_rect.size.height <= (local_rect.size.y / zoom)) {
if (ABS(begin.y - previous_update_view_offset.y) < ABS(begin.y - view_offset.y)) { if (constrain_editor_view && ABS(begin.y - previous_update_view_offset.y) < ABS(begin.y - view_offset.y)) {
view_offset.y = previous_update_view_offset.y; view_offset.y = previous_update_view_offset.y;
} }
v_scroll->hide(); v_scroll->hide();
} else { } else {
if (view_offset.y > end.y && view_offset.y > previous_update_view_offset.y) { if (constrain_editor_view && view_offset.y > end.y && view_offset.y > previous_update_view_offset.y) {
view_offset.y = MAX(end.y, previous_update_view_offset.y); view_offset.y = MAX(end.y, previous_update_view_offset.y);
} }
if (view_offset.y < begin.y && view_offset.y < previous_update_view_offset.y) { if (constrain_editor_view && view_offset.y < begin.y && view_offset.y < previous_update_view_offset.y) {
view_offset.y = MIN(begin.y, previous_update_view_offset.y); view_offset.y = MIN(begin.y, previous_update_view_offset.y);
} }
@ -3569,16 +3570,16 @@ void CanvasItemEditor::_update_scrollbars() {
} }
if (canvas_item_rect.size.width <= (local_rect.size.x / zoom)) { if (canvas_item_rect.size.width <= (local_rect.size.x / zoom)) {
if (ABS(begin.x - previous_update_view_offset.x) < ABS(begin.x - view_offset.x)) { if (constrain_editor_view && ABS(begin.x - previous_update_view_offset.x) < ABS(begin.x - view_offset.x)) {
view_offset.x = previous_update_view_offset.x; view_offset.x = previous_update_view_offset.x;
} }
h_scroll->hide(); h_scroll->hide();
} else { } else {
if (view_offset.x > end.x && view_offset.x > previous_update_view_offset.x) { if (constrain_editor_view && view_offset.x > end.x && view_offset.x > previous_update_view_offset.x) {
view_offset.x = MAX(end.x, previous_update_view_offset.x); view_offset.x = MAX(end.x, previous_update_view_offset.x);
} }
if (view_offset.x < begin.x && view_offset.x < previous_update_view_offset.x) { if (constrain_editor_view && view_offset.x < begin.x && view_offset.x < previous_update_view_offset.x) {
view_offset.x = MIN(begin.x, previous_update_view_offset.x); view_offset.x = MIN(begin.x, previous_update_view_offset.x);
} }
@ -3903,6 +3904,7 @@ void CanvasItemEditor::_popup_callback(int p_op) {
show_rulers = !show_rulers; show_rulers = !show_rulers;
int idx = view_menu->get_popup()->get_item_index(SHOW_RULERS); int idx = view_menu->get_popup()->get_item_index(SHOW_RULERS);
view_menu->get_popup()->set_item_checked(idx, show_rulers); view_menu->get_popup()->set_item_checked(idx, show_rulers);
_update_scrollbars();
viewport->update(); viewport->update();
} break; } break;
case SHOW_GUIDES: { case SHOW_GUIDES: {
@ -4371,6 +4373,7 @@ Dictionary CanvasItemEditor::get_state() const {
state["show_rulers"] = show_rulers; state["show_rulers"] = show_rulers;
state["show_guides"] = show_guides; state["show_guides"] = show_guides;
state["show_helpers"] = show_helpers; state["show_helpers"] = show_helpers;
state["show_zoom_control"] = zoom_hb->is_visible();
state["show_edit_locks"] = show_edit_locks; state["show_edit_locks"] = show_edit_locks;
state["snap_rotation"] = snap_rotation; state["snap_rotation"] = snap_rotation;
state["snap_relative"] = snap_relative; state["snap_relative"] = snap_relative;
@ -4381,6 +4384,7 @@ Dictionary CanvasItemEditor::get_state() const {
void CanvasItemEditor::set_state(const Dictionary &p_state) { void CanvasItemEditor::set_state(const Dictionary &p_state) {
bool update_scrollbars = false;
Dictionary state = p_state; Dictionary state = p_state;
if (state.has("zoom")) { if (state.has("zoom")) {
zoom = p_state["zoom"]; zoom = p_state["zoom"];
@ -4389,7 +4393,7 @@ void CanvasItemEditor::set_state(const Dictionary &p_state) {
if (state.has("ofs")) { if (state.has("ofs")) {
view_offset = p_state["ofs"]; view_offset = p_state["ofs"];
previous_update_view_offset = view_offset; previous_update_view_offset = view_offset;
_update_scrollbars(); update_scrollbars = true;
} }
if (state.has("grid_offset")) { if (state.has("grid_offset")) {
@ -4477,6 +4481,7 @@ void CanvasItemEditor::set_state(const Dictionary &p_state) {
show_rulers = state["show_rulers"]; show_rulers = state["show_rulers"];
int idx = view_menu->get_popup()->get_item_index(SHOW_RULERS); int idx = view_menu->get_popup()->get_item_index(SHOW_RULERS);
view_menu->get_popup()->set_item_checked(idx, show_rulers); view_menu->get_popup()->set_item_checked(idx, show_rulers);
update_scrollbars = true;
} }
if (state.has("show_guides")) { if (state.has("show_guides")) {
@ -4497,6 +4502,11 @@ void CanvasItemEditor::set_state(const Dictionary &p_state) {
view_menu->get_popup()->set_item_checked(idx, show_edit_locks); view_menu->get_popup()->set_item_checked(idx, show_edit_locks);
} }
if (state.has("show_zoom_control")) {
// This one is not user-controllable, but instrumentable
zoom_hb->set_visible(state["show_zoom_control"]);
}
if (state.has("snap_rotation")) { if (state.has("snap_rotation")) {
snap_rotation = state["snap_rotation"]; snap_rotation = state["snap_rotation"];
int idx = snap_config_menu->get_popup()->get_item_index(SNAP_USE_ROTATION); int idx = snap_config_menu->get_popup()->get_item_index(SNAP_USE_ROTATION);
@ -4521,6 +4531,9 @@ void CanvasItemEditor::set_state(const Dictionary &p_state) {
skeleton_menu->get_popup()->set_item_checked(idx, skeleton_show_bones); skeleton_menu->get_popup()->set_item_checked(idx, skeleton_show_bones);
} }
if (update_scrollbars) {
_update_scrollbars();
}
viewport->update(); viewport->update();
} }

View file

@ -1906,10 +1906,11 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra
String flags = EditorSettings::get_singleton()->get("text_editor/external/exec_flags"); String flags = EditorSettings::get_singleton()->get("text_editor/external/exec_flags");
List<String> args; List<String> args;
bool has_file_flag = false;
String script_path = ProjectSettings::get_singleton()->globalize_path(p_resource->get_path());
if (flags.size()) { if (flags.size()) {
String project_path = ProjectSettings::get_singleton()->get_resource_path(); String project_path = ProjectSettings::get_singleton()->get_resource_path();
String script_path = ProjectSettings::get_singleton()->globalize_path(p_resource->get_path());
flags = flags.replacen("{line}", itos(p_line > 0 ? p_line : 0)); flags = flags.replacen("{line}", itos(p_line > 0 ? p_line : 0));
flags = flags.replacen("{col}", itos(p_col)); flags = flags.replacen("{col}", itos(p_col));
@ -1931,6 +1932,9 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra
} else if (flags[i] == '\0' || (!inside_quotes && flags[i] == ' ')) { } else if (flags[i] == '\0' || (!inside_quotes && flags[i] == ' ')) {
String arg = flags.substr(from, num_chars); String arg = flags.substr(from, num_chars);
if (arg.find("{file}") != -1) {
has_file_flag = true;
}
// do path replacement here, else there will be issues with spaces and quotes // do path replacement here, else there will be issues with spaces and quotes
arg = arg.replacen("{project}", project_path); arg = arg.replacen("{project}", project_path);
@ -1945,6 +1949,11 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra
} }
} }
// Default to passing script path if no {file} flag is specified.
if (!has_file_flag) {
args.push_back(script_path);
}
Error err = OS::get_singleton()->execute(path, args, false); Error err = OS::get_singleton()->execute(path, args, false);
if (err == OK) if (err == OK)
return false; return false;
@ -3331,7 +3340,8 @@ ScriptEditorPlugin::ScriptEditorPlugin(EditorNode *p_node) {
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "text_editor/open_scripts/list_script_names_as", PROPERTY_HINT_ENUM, "Name,Parent Directory And Name,Full Path")); EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "text_editor/open_scripts/list_script_names_as", PROPERTY_HINT_ENUM, "Name,Parent Directory And Name,Full Path"));
EDITOR_DEF("text_editor/open_scripts/list_script_names_as", 0); EDITOR_DEF("text_editor/open_scripts/list_script_names_as", 0);
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "text_editor/external/exec_path", PROPERTY_HINT_GLOBAL_FILE)); EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "text_editor/external/exec_path", PROPERTY_HINT_GLOBAL_FILE));
EDITOR_DEF("text_editor/external/exec_flags", ""); EDITOR_DEF("text_editor/external/exec_flags", "{file}");
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "text_editor/external/exec_flags", PROPERTY_HINT_PLACEHOLDER_TEXT, "Call flags with placeholders: {project}, {file}, {col}, {line}."));
ED_SHORTCUT("script_editor/open_recent", TTR("Open Recent"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_T); ED_SHORTCUT("script_editor/open_recent", TTR("Open Recent"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_T);
ED_SHORTCUT("script_editor/clear_recent", TTR("Clear Recent Files")); ED_SHORTCUT("script_editor/clear_recent", TTR("Clear Recent Files"));

View file

@ -165,7 +165,7 @@ void ScriptTextEditor::_load_theme_settings() {
text_edit->add_color_override("safe_line_number_color", safe_line_number_color); text_edit->add_color_override("safe_line_number_color", safe_line_number_color);
text_edit->add_color_override("caret_color", caret_color); text_edit->add_color_override("caret_color", caret_color);
text_edit->add_color_override("caret_background_color", caret_background_color); text_edit->add_color_override("caret_background_color", caret_background_color);
text_edit->add_color_override("font_selected_color", text_selected_color); text_edit->add_color_override("font_color_selected", text_selected_color);
text_edit->add_color_override("selection_color", selection_color); text_edit->add_color_override("selection_color", selection_color);
text_edit->add_color_override("brace_mismatch_color", brace_mismatch_color); text_edit->add_color_override("brace_mismatch_color", brace_mismatch_color);
text_edit->add_color_override("current_line_color", current_line_color); text_edit->add_color_override("current_line_color", current_line_color);
@ -1329,7 +1329,9 @@ void ScriptTextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) {
if (has_color) { if (has_color) {
String line = tx->get_line(row); String line = tx->get_line(row);
color_line = row; color_position.x = row;
color_position.y = col;
int begin = 0; int begin = 0;
int end = 0; int end = 0;
bool valid = false; bool valid = false;
@ -1369,10 +1371,15 @@ void ScriptTextEditor::_color_changed(const Color &p_color) {
new_args = String("(" + rtos(p_color.r) + ", " + rtos(p_color.g) + ", " + rtos(p_color.b) + ", " + rtos(p_color.a) + ")"); new_args = String("(" + rtos(p_color.r) + ", " + rtos(p_color.g) + ", " + rtos(p_color.b) + ", " + rtos(p_color.a) + ")");
} }
String line = code_editor->get_text_edit()->get_line(color_line); String line = code_editor->get_text_edit()->get_line(color_position.x);
String new_line = line.replace(color_args, new_args); int color_args_pos = line.find(color_args, color_position.y);
String line_with_replaced_args = line;
line_with_replaced_args.erase(color_args_pos, color_args.length());
line_with_replaced_args = line_with_replaced_args.insert(color_args_pos, new_args);
color_args = new_args; color_args = new_args;
code_editor->get_text_edit()->set_line(color_line, new_line); code_editor->get_text_edit()->set_line(color_position.x, line_with_replaced_args);
code_editor->get_text_edit()->update();
} }
void ScriptTextEditor::_make_context_menu(bool p_selection, bool p_color, bool p_foldable, bool p_open_docs, bool p_goto_definition) { void ScriptTextEditor::_make_context_menu(bool p_selection, bool p_color, bool p_foldable, bool p_open_docs, bool p_goto_definition) {
@ -1465,6 +1472,7 @@ ScriptTextEditor::ScriptTextEditor() {
color_panel = memnew(PopupPanel); color_panel = memnew(PopupPanel);
add_child(color_panel); add_child(color_panel);
color_picker = memnew(ColorPicker); color_picker = memnew(ColorPicker);
color_picker->set_deferred_mode(true);
color_panel->add_child(color_picker); color_panel->add_child(color_picker);
color_picker->connect("color_changed", this, "_color_changed"); color_picker->connect("color_changed", this, "_color_changed");

View file

@ -59,7 +59,7 @@ class ScriptTextEditor : public ScriptEditorBase {
PopupPanel *color_panel; PopupPanel *color_panel;
ColorPicker *color_picker; ColorPicker *color_picker;
int color_line; Vector2 color_position;
String color_args; String color_args;
void _update_member_keywords(); void _update_member_keywords();

View file

@ -102,7 +102,7 @@ void ShaderTextEditor::_load_theme_settings() {
get_text_edit()->add_color_override("line_number_color", line_number_color); get_text_edit()->add_color_override("line_number_color", line_number_color);
get_text_edit()->add_color_override("caret_color", caret_color); get_text_edit()->add_color_override("caret_color", caret_color);
get_text_edit()->add_color_override("caret_background_color", caret_background_color); get_text_edit()->add_color_override("caret_background_color", caret_background_color);
get_text_edit()->add_color_override("font_selected_color", text_selected_color); get_text_edit()->add_color_override("font_color_selected", text_selected_color);
get_text_edit()->add_color_override("selection_color", selection_color); get_text_edit()->add_color_override("selection_color", selection_color);
get_text_edit()->add_color_override("brace_mismatch_color", brace_mismatch_color); get_text_edit()->add_color_override("brace_mismatch_color", brace_mismatch_color);
get_text_edit()->add_color_override("current_line_color", current_line_color); get_text_edit()->add_color_override("current_line_color", current_line_color);
@ -346,6 +346,9 @@ void ShaderEditor::_menu_option(int p_option) {
goto_line_dialog->popup_find_line(shader_editor->get_text_edit()); goto_line_dialog->popup_find_line(shader_editor->get_text_edit());
} break; } break;
case HELP_DOCS: {
OS::get_singleton()->shell_open("https://docs.godotengine.org/en/stable/tutorials/shading/shading_reference/index.html");
} break;
} }
if (p_option != SEARCH_FIND && p_option != SEARCH_REPLACE && p_option != SEARCH_GOTO_LINE) { if (p_option != SEARCH_FIND && p_option != SEARCH_REPLACE && p_option != SEARCH_GOTO_LINE) {
shader_editor->get_text_edit()->call_deferred("grab_focus"); shader_editor->get_text_edit()->call_deferred("grab_focus");
@ -577,10 +580,17 @@ ShaderEditor::ShaderEditor(EditorNode *p_node) {
search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_line"), SEARCH_GOTO_LINE); search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_line"), SEARCH_GOTO_LINE);
search_menu->get_popup()->connect("id_pressed", this, "_menu_option"); search_menu->get_popup()->connect("id_pressed", this, "_menu_option");
help_menu = memnew(MenuButton);
help_menu->set_text(TTR("Help"));
help_menu->set_switch_on_hover(true);
help_menu->get_popup()->add_icon_item(p_node->get_gui_base()->get_icon("Instance", "EditorIcons"), TTR("Online Docs"), HELP_DOCS);
help_menu->get_popup()->connect("id_pressed", this, "_menu_option");
add_child(main_container); add_child(main_container);
main_container->add_child(hbc); main_container->add_child(hbc);
hbc->add_child(search_menu); hbc->add_child(search_menu);
hbc->add_child(edit_menu); hbc->add_child(edit_menu);
hbc->add_child(help_menu);
hbc->add_style_override("panel", p_node->get_gui_base()->get_stylebox("ScriptEditorPanel", "EditorStyles")); hbc->add_style_override("panel", p_node->get_gui_base()->get_stylebox("ScriptEditorPanel", "EditorStyles"));
main_container->add_child(shader_editor); main_container->add_child(shader_editor);

View file

@ -88,12 +88,12 @@ class ShaderEditor : public PanelContainer {
SEARCH_FIND_PREV, SEARCH_FIND_PREV,
SEARCH_REPLACE, SEARCH_REPLACE,
SEARCH_GOTO_LINE, SEARCH_GOTO_LINE,
HELP_DOCS,
}; };
MenuButton *edit_menu; MenuButton *edit_menu;
MenuButton *search_menu; MenuButton *search_menu;
MenuButton *settings_menu; MenuButton *help_menu;
PopupMenu *context_menu; PopupMenu *context_menu;
uint64_t idle; uint64_t idle;

View file

@ -5323,6 +5323,7 @@ void SpatialEditor::_register_all_gizmos() {
add_gizmo_plugin(Ref<VehicleWheelSpatialGizmoPlugin>(memnew(VehicleWheelSpatialGizmoPlugin))); add_gizmo_plugin(Ref<VehicleWheelSpatialGizmoPlugin>(memnew(VehicleWheelSpatialGizmoPlugin)));
add_gizmo_plugin(Ref<VisibilityNotifierGizmoPlugin>(memnew(VisibilityNotifierGizmoPlugin))); add_gizmo_plugin(Ref<VisibilityNotifierGizmoPlugin>(memnew(VisibilityNotifierGizmoPlugin)));
add_gizmo_plugin(Ref<ParticlesGizmoPlugin>(memnew(ParticlesGizmoPlugin))); add_gizmo_plugin(Ref<ParticlesGizmoPlugin>(memnew(ParticlesGizmoPlugin)));
add_gizmo_plugin(Ref<CPUParticlesGizmoPlugin>(memnew(CPUParticlesGizmoPlugin)));
add_gizmo_plugin(Ref<ReflectionProbeGizmoPlugin>(memnew(ReflectionProbeGizmoPlugin))); add_gizmo_plugin(Ref<ReflectionProbeGizmoPlugin>(memnew(ReflectionProbeGizmoPlugin)));
add_gizmo_plugin(Ref<GIProbeGizmoPlugin>(memnew(GIProbeGizmoPlugin))); add_gizmo_plugin(Ref<GIProbeGizmoPlugin>(memnew(GIProbeGizmoPlugin)));
add_gizmo_plugin(Ref<BakedIndirectLightGizmoPlugin>(memnew(BakedIndirectLightGizmoPlugin))); add_gizmo_plugin(Ref<BakedIndirectLightGizmoPlugin>(memnew(BakedIndirectLightGizmoPlugin)));

View file

@ -115,7 +115,7 @@ void TextEditor::_load_theme_settings() {
text_edit->add_color_override("line_number_color", line_number_color); text_edit->add_color_override("line_number_color", line_number_color);
text_edit->add_color_override("caret_color", caret_color); text_edit->add_color_override("caret_color", caret_color);
text_edit->add_color_override("caret_background_color", caret_background_color); text_edit->add_color_override("caret_background_color", caret_background_color);
text_edit->add_color_override("font_selected_color", text_selected_color); text_edit->add_color_override("font_color_selected", text_selected_color);
text_edit->add_color_override("selection_color", selection_color); text_edit->add_color_override("selection_color", selection_color);
text_edit->add_color_override("brace_mismatch_color", brace_mismatch_color); text_edit->add_color_override("brace_mismatch_color", brace_mismatch_color);
text_edit->add_color_override("current_line_color", current_line_color); text_edit->add_color_override("current_line_color", current_line_color);

View file

@ -878,11 +878,9 @@ ThemeEditor::ThemeEditor() {
void ThemeEditorPlugin::edit(Object *p_node) { void ThemeEditorPlugin::edit(Object *p_node) {
if (Object::cast_to<Theme>(p_node)) { if (Object::cast_to<Theme>(p_node)) {
theme_editor->show();
theme_editor->edit(Object::cast_to<Theme>(p_node)); theme_editor->edit(Object::cast_to<Theme>(p_node));
} else { } else {
theme_editor->edit(Ref<Theme>()); theme_editor->edit(Ref<Theme>());
theme_editor->hide();
} }
} }
@ -897,11 +895,11 @@ void ThemeEditorPlugin::make_visible(bool p_visible) {
theme_editor->set_process(true); theme_editor->set_process(true);
button->show(); button->show();
editor->make_bottom_panel_item_visible(theme_editor); editor->make_bottom_panel_item_visible(theme_editor);
} else { } else {
theme_editor->set_process(false); theme_editor->set_process(false);
if (theme_editor->is_visible_in_tree()) if (theme_editor->is_visible_in_tree())
editor->hide_bottom_panel(); editor->hide_bottom_panel();
button->hide(); button->hide();
} }
} }

View file

@ -363,6 +363,8 @@ void TileMapEditor::_update_palette() {
// Update the palette // Update the palette
Vector<int> selected = get_selected_tiles(); Vector<int> selected = get_selected_tiles();
int selected_single = palette->get_current();
int selected_manual = manual_palette->get_current();
palette->clear(); palette->clear();
manual_palette->clear(); manual_palette->clear();
manual_palette->hide(); manual_palette->hide();
@ -470,7 +472,7 @@ void TileMapEditor::_update_palette() {
if (selected.get(0) != TileMap::INVALID_CELL) { if (selected.get(0) != TileMap::INVALID_CELL) {
set_selected_tiles(selected); set_selected_tiles(selected);
sel_tile = selected.get(Math::rand() % selected.size()); sel_tile = selected.get(Math::rand() % selected.size());
} else { } else if (palette->get_item_count() > 0) {
palette->select(0); palette->select(0);
} }
@ -511,9 +513,10 @@ void TileMapEditor::_update_palette() {
if (manual_palette->get_item_count() > 0) { if (manual_palette->get_item_count() > 0) {
// Only show the manual palette if at least tile exists in it // Only show the manual palette if at least tile exists in it
int selected2 = manual_palette->get_current(); if (selected_manual == -1 || selected_single != palette->get_current())
if (selected2 == -1) selected2 = 0; selected_manual = 0;
manual_palette->set_current(selected2); if (selected_manual < manual_palette->get_item_count())
manual_palette->set_current(selected_manual);
manual_palette->show(); manual_palette->show();
} }
@ -1434,9 +1437,9 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
aabb.expand_to(node->world_to_map(xform_inv.xform(screen_size))); aabb.expand_to(node->world_to_map(xform_inv.xform(screen_size)));
Rect2i si = aabb.grow(1.0); Rect2i si = aabb.grow(1.0);
if (node->get_half_offset() != TileMap::HALF_OFFSET_X) { if (node->get_half_offset() != TileMap::HALF_OFFSET_X && node->get_half_offset() != TileMap::HALF_OFFSET_NEGATIVE_X) {
int max_lines = 2000; //avoid crash if size too smal int max_lines = 2000; //avoid crash if size too small
for (int i = (si.position.x) - 1; i <= (si.position.x + si.size.x); i++) { for (int i = (si.position.x) - 1; i <= (si.position.x + si.size.x); i++) {
@ -1450,7 +1453,7 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
} }
} else { } else {
int max_lines = 10000; //avoid crash if size too smal int max_lines = 10000; //avoid crash if size too small
for (int i = (si.position.x) - 1; i <= (si.position.x + si.size.x); i++) { for (int i = (si.position.x) - 1; i <= (si.position.x + si.size.x); i++) {
@ -1458,7 +1461,7 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
Vector2 ofs; Vector2 ofs;
if (ABS(j) & 1) { if (ABS(j) & 1) {
ofs = cell_xf[0] * 0.5; ofs = cell_xf[0] * (node->get_half_offset() == TileMap::HALF_OFFSET_X ? 0.5 : -0.5);
} }
Vector2 from = xform.xform(node->map_to_world(Vector2(i, j), true) + ofs); Vector2 from = xform.xform(node->map_to_world(Vector2(i, j), true) + ofs);
@ -1477,7 +1480,7 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
int max_lines = 10000; //avoid crash if size too smal int max_lines = 10000; //avoid crash if size too smal
if (node->get_half_offset() != TileMap::HALF_OFFSET_Y) { if (node->get_half_offset() != TileMap::HALF_OFFSET_Y && node->get_half_offset() != TileMap::HALF_OFFSET_NEGATIVE_Y) {
for (int i = (si.position.y) - 1; i <= (si.position.y + si.size.y); i++) { for (int i = (si.position.y) - 1; i <= (si.position.y + si.size.y); i++) {
@ -1498,7 +1501,7 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
Vector2 ofs; Vector2 ofs;
if (ABS(j) & 1) { if (ABS(j) & 1) {
ofs = cell_xf[1] * 0.5; ofs = cell_xf[1] * (node->get_half_offset() == TileMap::HALF_OFFSET_Y ? 0.5 : -0.5);
} }
Vector2 from = xform.xform(node->map_to_world(Vector2(j, i), true) + ofs); Vector2 from = xform.xform(node->map_to_world(Vector2(j, i), true) + ofs);
@ -1539,8 +1542,12 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
if (node->get_half_offset() == TileMap::HALF_OFFSET_X && ABS(over_tile.y) & 1) if (node->get_half_offset() == TileMap::HALF_OFFSET_X && ABS(over_tile.y) & 1)
endpoints[i] += cell_xf[0] * 0.5; endpoints[i] += cell_xf[0] * 0.5;
if (node->get_half_offset() == TileMap::HALF_OFFSET_NEGATIVE_X && ABS(over_tile.y) & 1)
endpoints[i] += cell_xf[0] * -0.5;
if (node->get_half_offset() == TileMap::HALF_OFFSET_Y && ABS(over_tile.x) & 1) if (node->get_half_offset() == TileMap::HALF_OFFSET_Y && ABS(over_tile.x) & 1)
endpoints[i] += cell_xf[1] * 0.5; endpoints[i] += cell_xf[1] * 0.5;
if (node->get_half_offset() == TileMap::HALF_OFFSET_NEGATIVE_Y && ABS(over_tile.x) & 1)
endpoints[i] += cell_xf[1] * -0.5;
endpoints[i] = xform.xform(endpoints[i]); endpoints[i] = xform.xform(endpoints[i]);
} }
Color col; Color col;

View file

@ -1609,40 +1609,28 @@ void ProjectManager::_show_project(const String &p_path) {
OS::get_singleton()->shell_open(String("file://") + p_path); OS::get_singleton()->shell_open(String("file://") + p_path);
} }
void ProjectManager::_scan_dir(DirAccess *da, float pos, float total, List<String> *r_projects) { void ProjectManager::_scan_dir(const String &path, List<String> *r_projects) {
DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
List<String> subdirs; da->change_dir(path);
da->list_dir_begin(); da->list_dir_begin();
String n = da->get_next(); String n = da->get_next();
while (n != String()) { while (n != String()) {
if (da->current_is_dir() && !n.begins_with(".")) { if (da->current_is_dir() && !n.begins_with(".")) {
subdirs.push_front(n); _scan_dir(da->get_current_dir().plus_file(n), r_projects);
} else if (n == "project.godot") { } else if (n == "project.godot") {
r_projects->push_back(da->get_current_dir()); r_projects->push_back(da->get_current_dir());
} }
n = da->get_next(); n = da->get_next();
} }
da->list_dir_end(); da->list_dir_end();
int m = 0; memdelete(da);
for (List<String>::Element *E = subdirs.front(); E; E = E->next()) {
da->change_dir(E->get());
float slice = total / subdirs.size();
_scan_dir(da, pos + slice * m, slice, r_projects);
da->change_dir("..");
m++;
}
} }
void ProjectManager::_scan_begin(const String &p_base) { void ProjectManager::_scan_begin(const String &p_base) {
print_line("Scanning projects at: " + p_base); print_line("Scanning projects at: " + p_base);
List<String> projects; List<String> projects;
DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); _scan_dir(p_base, &projects);
da->change_dir(p_base);
_scan_dir(da, 0, 1, &projects);
memdelete(da);
print_line("Found " + itos(projects.size()) + " projects."); print_line("Found " + itos(projects.size()) + " projects.");
for (List<String>::Element *E = projects.front(); E; E = E->next()) { for (List<String>::Element *E = projects.front(); E; E = E->next()) {

View file

@ -102,7 +102,7 @@ class ProjectManager : public Control {
void _on_project_created(const String &dir); void _on_project_created(const String &dir);
void _on_projects_updated(); void _on_projects_updated();
void _update_scroll_position(const String &dir); void _update_scroll_position(const String &dir);
void _scan_dir(DirAccess *da, float pos, float total, List<String> *r_projects); void _scan_dir(const String &path, List<String> *r_projects);
void _install_project(const String &p_zip_path, const String &p_title); void _install_project(const String &p_zip_path, const String &p_title);

View file

@ -36,6 +36,7 @@
#include "scene/3d/baked_lightmap.h" #include "scene/3d/baked_lightmap.h"
#include "scene/3d/collision_polygon.h" #include "scene/3d/collision_polygon.h"
#include "scene/3d/collision_shape.h" #include "scene/3d/collision_shape.h"
#include "scene/3d/cpu_particles.h"
#include "scene/3d/gi_probe.h" #include "scene/3d/gi_probe.h"
#include "scene/3d/light.h" #include "scene/3d/light.h"
#include "scene/3d/listener.h" #include "scene/3d/listener.h"
@ -571,9 +572,11 @@ bool EditorSpatialGizmo::intersect_ray(Camera *p_camera, const Point2 &p_point,
Transform orig_camera_transform = p_camera->get_camera_transform(); Transform orig_camera_transform = p_camera->get_camera_transform();
if (orig_camera_transform.origin.distance_squared_to(t.origin) > 0.01) { if (orig_camera_transform.origin.distance_squared_to(t.origin) > 0.01 &&
ABS(orig_camera_transform.basis.get_axis(Vector3::AXIS_Z).dot(Vector3(0, 1, 0))) < 0.99) {
p_camera->look_at(t.origin, Vector3(0, 1, 0)); p_camera->look_at(t.origin, Vector3(0, 1, 0));
} }
Vector3 c0 = t.xform(Vector3(selectable_icon_size, selectable_icon_size, 0) * scale); Vector3 c0 = t.xform(Vector3(selectable_icon_size, selectable_icon_size, 0) * scale);
Vector3 c1 = t.xform(Vector3(-selectable_icon_size, -selectable_icon_size, 0) * scale); Vector3 c1 = t.xform(Vector3(-selectable_icon_size, -selectable_icon_size, 0) * scale);
@ -582,7 +585,7 @@ bool EditorSpatialGizmo::intersect_ray(Camera *p_camera, const Point2 &p_point,
p_camera->set_global_transform(orig_camera_transform); p_camera->set_global_transform(orig_camera_transform);
Rect2 rect(p0, p1 - p0); Rect2 rect(p0, (p1 - p0).abs());
rect.set_position(center - rect.get_size() / 2.0); rect.set_position(center - rect.get_size() / 2.0);
@ -2373,6 +2376,33 @@ void VisibilityNotifierGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
//// ////
CPUParticlesGizmoPlugin::CPUParticlesGizmoPlugin() {
create_icon_material("particles_icon", SpatialEditor::get_singleton()->get_icon("GizmoCPUParticles", "EditorIcons"));
}
bool CPUParticlesGizmoPlugin::has_gizmo(Spatial *p_spatial) {
return Object::cast_to<CPUParticles>(p_spatial) != NULL;
}
String CPUParticlesGizmoPlugin::get_name() const {
return "CPUParticles";
}
int CPUParticlesGizmoPlugin::get_priority() const {
return -1;
}
bool CPUParticlesGizmoPlugin::is_selectable_when_hidden() const {
return true;
}
void CPUParticlesGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
Ref<Material> icon = get_material("particles_icon", p_gizmo);
p_gizmo->add_unscaled_billboard(icon, 0.05);
}
////
ParticlesGizmoPlugin::ParticlesGizmoPlugin() { ParticlesGizmoPlugin::ParticlesGizmoPlugin() {
Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/particles", Color(0.8, 0.7, 0.4)); Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/particles", Color(0.8, 0.7, 0.4));
create_material("particles_material", gizmo_color); create_material("particles_material", gizmo_color);

View file

@ -249,6 +249,18 @@ public:
VisibilityNotifierGizmoPlugin(); VisibilityNotifierGizmoPlugin();
}; };
class CPUParticlesGizmoPlugin : public EditorSpatialGizmoPlugin {
GDCLASS(CPUParticlesGizmoPlugin, EditorSpatialGizmoPlugin);
public:
bool has_gizmo(Spatial *p_spatial);
String get_name() const;
int get_priority() const;
bool is_selectable_when_hidden() const;
void redraw(EditorSpatialGizmo *p_gizmo);
CPUParticlesGizmoPlugin();
};
class ParticlesGizmoPlugin : public EditorSpatialGizmoPlugin { class ParticlesGizmoPlugin : public EditorSpatialGizmoPlugin {
GDCLASS(ParticlesGizmoPlugin, EditorSpatialGizmoPlugin); GDCLASS(ParticlesGizmoPlugin, EditorSpatialGizmoPlugin);

View file

@ -627,7 +627,8 @@ bool InputDefault::is_emulating_mouse_from_touch() const {
return emulate_mouse_from_touch; return emulate_mouse_from_touch;
} }
Input::CursorShape InputDefault::get_default_cursor_shape() { Input::CursorShape InputDefault::get_default_cursor_shape() const {
return default_shape; return default_shape;
} }
@ -646,6 +647,11 @@ void InputDefault::set_default_cursor_shape(CursorShape p_shape) {
parse_input_event(mm); parse_input_event(mm);
} }
Input::CursorShape InputDefault::get_current_cursor_shape() const {
return (Input::CursorShape)OS::get_singleton()->get_cursor_shape();
}
void InputDefault::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { void InputDefault::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
if (Engine::get_singleton()->is_editor_hint()) if (Engine::get_singleton()->is_editor_hint())
return; return;
@ -653,21 +659,6 @@ void InputDefault::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_sh
OS::get_singleton()->set_custom_mouse_cursor(p_cursor, (OS::CursorShape)p_shape, p_hotspot); OS::get_singleton()->set_custom_mouse_cursor(p_cursor, (OS::CursorShape)p_shape, p_hotspot);
} }
void InputDefault::set_mouse_in_window(bool p_in_window) {
/* no longer supported, leaving this for reference to anyone who might want to implement hardware cursors
if (custom_cursor.is_valid()) {
if (p_in_window) {
set_mouse_mode(MOUSE_MODE_HIDDEN);
VisualServer::get_singleton()->cursor_set_visible(true);
} else {
set_mouse_mode(MOUSE_MODE_VISIBLE);
VisualServer::get_singleton()->cursor_set_visible(false);
}
}
*/
}
void InputDefault::accumulate_input_event(const Ref<InputEvent> &p_event) { void InputDefault::accumulate_input_event(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null()); ERR_FAIL_COND(p_event.is_null());

View file

@ -243,10 +243,10 @@ public:
void set_emulate_mouse_from_touch(bool p_emulate); void set_emulate_mouse_from_touch(bool p_emulate);
virtual bool is_emulating_mouse_from_touch() const; virtual bool is_emulating_mouse_from_touch() const;
virtual CursorShape get_default_cursor_shape(); virtual CursorShape get_default_cursor_shape() const;
virtual void set_default_cursor_shape(CursorShape p_shape); virtual void set_default_cursor_shape(CursorShape p_shape);
virtual CursorShape get_current_cursor_shape() const;
virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape = Input::CURSOR_ARROW, const Vector2 &p_hotspot = Vector2()); virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape = Input::CURSOR_ARROW, const Vector2 &p_hotspot = Vector2());
virtual void set_mouse_in_window(bool p_in_window);
void parse_mapping(String p_mapping); void parse_mapping(String p_mapping);
void joy_button(int p_device, int p_button, bool p_pressed); void joy_button(int p_device, int p_button, bool p_pressed);

View file

@ -204,7 +204,8 @@ void finalize_physics() {
void Main::print_help(const char *p_binary) { void Main::print_help(const char *p_binary) {
print_line(String(VERSION_NAME) + " v" + get_full_version_string() + " - https://godotengine.org"); print_line(String(VERSION_NAME) + " v" + get_full_version_string() + " - " + String(VERSION_WEBSITE));
OS::get_singleton()->print("Free and open source software under the terms of the MIT license.\n");
OS::get_singleton()->print("(c) 2007-2019 Juan Linietsky, Ariel Manzur.\n"); OS::get_singleton()->print("(c) 2007-2019 Juan Linietsky, Ariel Manzur.\n");
OS::get_singleton()->print("(c) 2014-2019 Godot Engine contributors.\n"); OS::get_singleton()->print("(c) 2014-2019 Godot Engine contributors.\n");
OS::get_singleton()->print("\n"); OS::get_singleton()->print("\n");
@ -1087,6 +1088,9 @@ error:
Error Main::setup2(Thread::ID p_main_tid_override) { Error Main::setup2(Thread::ID p_main_tid_override) {
// Print engine name and version
print_line(String(VERSION_NAME) + " v" + get_full_version_string() + " - " + String(VERSION_WEBSITE));
if (p_main_tid_override) { if (p_main_tid_override) {
Thread::_main_thread_id = p_main_tid_override; Thread::_main_thread_id = p_main_tid_override;
} }

View file

@ -61,6 +61,7 @@ def update_version(module_version_string=""):
f.write("#define VERSION_BUILD \"" + str(build_name) + "\"\n") f.write("#define VERSION_BUILD \"" + str(build_name) + "\"\n")
f.write("#define VERSION_MODULE_CONFIG \"" + str(version.module_config) + module_version_string + "\"\n") f.write("#define VERSION_MODULE_CONFIG \"" + str(version.module_config) + module_version_string + "\"\n")
f.write("#define VERSION_YEAR " + str(version.year) + "\n") f.write("#define VERSION_YEAR " + str(version.year) + "\n")
f.write("#define VERSION_WEBSITE \"" + str(version.website) + "\"\n")
f.close() f.close()
# NOTE: It is safe to generate this file here, since this is still executed serially # NOTE: It is safe to generate this file here, since this is still executed serially

View file

@ -162,8 +162,13 @@ $GODOT_HEAD_INCLUDE
requestAnimationFrame(animate); requestAnimationFrame(animate);
function adjustCanvasDimensions() { function adjustCanvasDimensions() {
canvas.width = innerWidth; var scale = window.devicePixelRatio || 1;
canvas.height = innerHeight; var width = window.innerWidth;
var height = window.innerHeight;
canvas.width = width * scale;
canvas.height = height * scale;
canvas.style.width = width + "px";
canvas.style.height = height + "px";
} }
animationCallbacks.push(adjustCanvasDimensions); animationCallbacks.push(adjustCanvasDimensions);
adjustCanvasDimensions(); adjustCanvasDimensions();

View file

@ -2060,6 +2060,9 @@ CSGBrush *CSGPolygon::_build_brush() {
for (int i = 0; i <= splits; i++) { for (int i = 0; i <= splits; i++) {
float ofs = i * path_interval; float ofs = i * path_interval;
if (ofs > bl) {
ofs = bl;
}
if (i == splits && path_joined) { if (i == splits && path_joined) {
ofs = 0.0; ofs = 0.0;
} }

View file

@ -243,7 +243,7 @@ void GDNativeLibrary::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_symbol_prefix", "symbol_prefix"), &GDNativeLibrary::set_symbol_prefix); ClassDB::bind_method(D_METHOD("set_symbol_prefix", "symbol_prefix"), &GDNativeLibrary::set_symbol_prefix);
ClassDB::bind_method(D_METHOD("set_reloadable", "reloadable"), &GDNativeLibrary::set_reloadable); ClassDB::bind_method(D_METHOD("set_reloadable", "reloadable"), &GDNativeLibrary::set_reloadable);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "config_file", PROPERTY_HINT_RESOURCE_TYPE, "ConfigFile"), "set_config_file", "get_config_file"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "config_file", PROPERTY_HINT_RESOURCE_TYPE, "ConfigFile", 0), "set_config_file", "get_config_file");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "load_once"), "set_load_once", "should_load_once"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "load_once"), "set_load_once", "should_load_once");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "singleton"), "set_singleton", "is_singleton"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "singleton"), "set_singleton", "is_singleton");

View file

@ -99,16 +99,20 @@ public:
} }
_FORCE_INLINE_ void set_load_once(bool p_load_once) { _FORCE_INLINE_ void set_load_once(bool p_load_once) {
config_file->set_value("general", "load_once", p_load_once);
load_once = p_load_once; load_once = p_load_once;
} }
_FORCE_INLINE_ void set_singleton(bool p_singleton) { _FORCE_INLINE_ void set_singleton(bool p_singleton) {
config_file->set_value("general", "singleton", p_singleton);
singleton = p_singleton; singleton = p_singleton;
} }
_FORCE_INLINE_ void set_symbol_prefix(String p_symbol_prefix) { _FORCE_INLINE_ void set_symbol_prefix(String p_symbol_prefix) {
config_file->set_value("general", "symbol_prefix", p_symbol_prefix);
symbol_prefix = p_symbol_prefix; symbol_prefix = p_symbol_prefix;
} }
_FORCE_INLINE_ void set_reloadable(bool p_reloadable) { _FORCE_INLINE_ void set_reloadable(bool p_reloadable) {
config_file->set_value("general", "reloadable", p_reloadable);
reloadable = p_reloadable; reloadable = p_reloadable;
} }

View file

@ -518,7 +518,7 @@ void GDAPI godot_variant_evaluate(godot_variant_operator p_op, const godot_varia
const Variant *a = (const Variant *)p_a; const Variant *a = (const Variant *)p_a;
const Variant *b = (const Variant *)p_b; const Variant *b = (const Variant *)p_b;
Variant *ret = (Variant *)r_ret; Variant *ret = (Variant *)r_ret;
Variant::evaluate(op, a, b, *ret, *r_valid); Variant::evaluate(op, *a, *b, *ret, *r_valid);
} }
#ifdef __cplusplus #ifdef __cplusplus

View file

@ -1309,7 +1309,7 @@ void NativeScriptLanguage::unregister_binding_functions(int p_idx) {
for (Set<Vector<void *> *>::Element *E = binding_instances.front(); E; E = E->next()) { for (Set<Vector<void *> *>::Element *E = binding_instances.front(); E; E = E->next()) {
Vector<void *> &binding_data = *E->get(); Vector<void *> &binding_data = *E->get();
if (binding_data[p_idx] && binding_functions[p_idx].second.free_instance_binding_data) if (p_idx < binding_data.size() && binding_data[p_idx] && binding_functions[p_idx].second.free_instance_binding_data)
binding_functions[p_idx].second.free_instance_binding_data(binding_functions[p_idx].second.data, binding_data[p_idx]); binding_functions[p_idx].second.free_instance_binding_data(binding_functions[p_idx].second.data, binding_data[p_idx]);
} }
@ -1345,7 +1345,7 @@ void *NativeScriptLanguage::get_instance_binding_data(int p_idx, Object *p_objec
if (!(*binding_data)[p_idx]) { if (!(*binding_data)[p_idx]) {
const void *global_type_tag = global_type_tags[p_idx].get(p_object->get_class_name()); const void *global_type_tag = get_global_type_tag(p_idx, p_object->get_class_name());
// no binding data yet, soooooo alloc new one \o/ // no binding data yet, soooooo alloc new one \o/
(*binding_data).write[p_idx] = binding_functions[p_idx].second.alloc_instance_binding_data(binding_functions[p_idx].second.data, global_type_tag, (godot_object *)p_object); (*binding_data).write[p_idx] = binding_functions[p_idx].second.alloc_instance_binding_data(binding_functions[p_idx].second.data, global_type_tag, (godot_object *)p_object);
@ -1454,6 +1454,9 @@ const void *NativeScriptLanguage::get_global_type_tag(int p_idx, StringName p_cl
const HashMap<StringName, const void *> &tags = global_type_tags[p_idx]; const HashMap<StringName, const void *> &tags = global_type_tags[p_idx];
if (!tags.has(p_class_name))
return NULL;
const void *tag = tags.get(p_class_name); const void *tag = tags.get(p_class_name);
return tag; return tag;

View file

@ -1945,6 +1945,10 @@ String GDScriptWarning::get_message() const {
CHECK_SYMBOLS(1); CHECK_SYMBOLS(1);
return "The local variable '" + symbols[0] + "' is declared but never used in the block."; return "The local variable '" + symbols[0] + "' is declared but never used in the block.";
} break; } break;
case SHADOWED_VARIABLE: {
CHECK_SYMBOLS(2);
return "The local variable '" + symbols[0] + "' is shadowing an already defined variable at line " + symbols[1] + ".";
} break;
case UNUSED_CLASS_VARIABLE: { case UNUSED_CLASS_VARIABLE: {
CHECK_SYMBOLS(1); CHECK_SYMBOLS(1);
return "The class variable '" + symbols[0] + "' is declared but never used in the script."; return "The class variable '" + symbols[0] + "' is declared but never used in the script.";
@ -2048,6 +2052,7 @@ String GDScriptWarning::get_name_from_code(Code p_code) {
"UNASSIGNED_VARIABLE", "UNASSIGNED_VARIABLE",
"UNASSIGNED_VARIABLE_OP_ASSIGN", "UNASSIGNED_VARIABLE_OP_ASSIGN",
"UNUSED_VARIABLE", "UNUSED_VARIABLE",
"SHADOWED_VARIABLE",
"UNUSED_CLASS_VARIABLE", "UNUSED_CLASS_VARIABLE",
"UNUSED_ARGUMENT", "UNUSED_ARGUMENT",
"UNREACHABLE_CODE", "UNREACHABLE_CODE",
@ -2129,6 +2134,7 @@ GDScriptLanguage::GDScriptLanguage() {
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
GLOBAL_DEF("debug/gdscript/warnings/enable", true); GLOBAL_DEF("debug/gdscript/warnings/enable", true);
GLOBAL_DEF("debug/gdscript/warnings/treat_warnings_as_errors", false); GLOBAL_DEF("debug/gdscript/warnings/treat_warnings_as_errors", false);
GLOBAL_DEF("debug/gdscript/warnings/exclude_addons", true);
GLOBAL_DEF("debug/gdscript/completion/autocomplete_setters_and_getters", false); GLOBAL_DEF("debug/gdscript/completion/autocomplete_setters_and_getters", false);
for (int i = 0; i < (int)GDScriptWarning::WARNING_MAX; i++) { for (int i = 0; i < (int)GDScriptWarning::WARNING_MAX; i++) {
String warning = GDScriptWarning::get_name_from_code((GDScriptWarning::Code)i).to_lower(); String warning = GDScriptWarning::get_name_from_code((GDScriptWarning::Code)i).to_lower();

View file

@ -273,6 +273,7 @@ struct GDScriptWarning {
UNASSIGNED_VARIABLE, // Variable used but never assigned UNASSIGNED_VARIABLE, // Variable used but never assigned
UNASSIGNED_VARIABLE_OP_ASSIGN, // Variable never assigned but used in an assignment operation (+=, *=, etc) UNASSIGNED_VARIABLE_OP_ASSIGN, // Variable never assigned but used in an assignment operation (+=, *=, etc)
UNUSED_VARIABLE, // Local variable is declared but never used UNUSED_VARIABLE, // Local variable is declared but never used
SHADOWED_VARIABLE, // Variable name shadowed by other variable
UNUSED_CLASS_VARIABLE, // Class variable is declared but never used in the file UNUSED_CLASS_VARIABLE, // Class variable is declared but never used in the file
UNUSED_ARGUMENT, // Function argument is never used UNUSED_ARGUMENT, // Function argument is never used
UNREACHABLE_CODE, // Code after a return statement UNREACHABLE_CODE, // Code after a return statement

View file

@ -133,35 +133,13 @@ Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_insta
return NULL; return NULL;
} }
String GDScriptFunction::_get_call_error(const Variant::CallError &p_err, const String &p_where, const Variant **argptrs) const {
String err_text;
if (p_err.error == Variant::CallError::CALL_ERROR_INVALID_ARGUMENT) {
int errorarg = p_err.argument;
err_text = "Invalid type in " + p_where + ". Cannot convert argument " + itos(errorarg + 1) + " from " + Variant::get_type_name(argptrs[errorarg]->get_type()) + " to " + Variant::get_type_name(p_err.expected) + ".";
} else if (p_err.error == Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS) {
err_text = "Invalid call to " + p_where + ". Expected " + itos(p_err.argument) + " arguments.";
} else if (p_err.error == Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS) {
err_text = "Invalid call to " + p_where + ". Expected " + itos(p_err.argument) + " arguments.";
} else if (p_err.error == Variant::CallError::CALL_ERROR_INVALID_METHOD) {
err_text = "Invalid call. Nonexistent " + p_where + ".";
} else if (p_err.error == Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL) {
err_text = "Attempt to call " + p_where + " on a null instance.";
} else {
err_text = "Bug, call error: #" + itos(p_err.error);
}
return err_text;
}
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
static String _get_var_type(const Variant *p_type) { static String _get_var_type(const Variant *p_var) {
String basestr; String basestr;
if (p_type->get_type() == Variant::OBJECT) { if (p_var->get_type() == Variant::OBJECT) {
Object *bobj = *p_type; Object *bobj = *p_var;
if (!bobj) { if (!bobj) {
basestr = "null instance"; basestr = "null instance";
} else { } else {
@ -176,12 +154,42 @@ static String _get_var_type(const Variant *p_type) {
} }
} else { } else {
basestr = Variant::get_type_name(p_type->get_type()); basestr = Variant::get_type_name(p_var->get_type());
} }
return basestr; return basestr;
} }
#endif #endif // DEBUG_ENABLED
String GDScriptFunction::_get_call_error(const Variant::CallError &p_err, const String &p_where, const Variant **argptrs) const {
String err_text;
if (p_err.error == Variant::CallError::CALL_ERROR_INVALID_ARGUMENT) {
int errorarg = p_err.argument;
// Handle the Object to Object case separately as we don't have further class details.
#ifdef DEBUG_ENABLED
if (p_err.expected == Variant::OBJECT && argptrs[errorarg]->get_type() == p_err.expected) {
err_text = "Invalid type in " + p_where + ". The Object-derived class of argument " + itos(errorarg + 1) + " (" + _get_var_type(argptrs[errorarg]) + ") is not a subclass of the expected argument class.";
} else
#endif // DEBUG_ENABLED
{
err_text = "Invalid type in " + p_where + ". Cannot convert argument " + itos(errorarg + 1) + " from " + Variant::get_type_name(argptrs[errorarg]->get_type()) + " to " + Variant::get_type_name(p_err.expected) + ".";
}
} else if (p_err.error == Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS) {
err_text = "Invalid call to " + p_where + ". Expected " + itos(p_err.argument) + " arguments.";
} else if (p_err.error == Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS) {
err_text = "Invalid call to " + p_where + ". Expected " + itos(p_err.argument) + " arguments.";
} else if (p_err.error == Variant::CallError::CALL_ERROR_INVALID_METHOD) {
err_text = "Invalid call. Nonexistent " + p_where + ".";
} else if (p_err.error == Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL) {
err_text = "Attempt to call " + p_where + " on a null instance.";
} else {
err_text = "Bug, call error: #" + itos(p_err.error);
}
return err_text;
}
#if defined(__GNUC__) #if defined(__GNUC__)
#define OPCODES_TABLE \ #define OPCODES_TABLE \

View file

@ -5238,6 +5238,7 @@ void GDScriptParser::_determine_inheritance(ClassNode *p_class) {
if (base_script.is_valid()) { if (base_script.is_valid()) {
String ident = base; String ident = base;
Ref<GDScript> find_subclass = base_script;
for (int i = extend_iter; i < p_class->extends_class.size(); i++) { for (int i = extend_iter; i < p_class->extends_class.size(); i++) {
@ -5247,7 +5248,7 @@ void GDScriptParser::_determine_inheritance(ClassNode *p_class) {
if (base_script->get_subclasses().has(subclass)) { if (base_script->get_subclasses().has(subclass)) {
base_script = base_script->get_subclasses()[subclass]; find_subclass = base_script->get_subclasses()[subclass];
} else if (base_script->get_constants().has(subclass)) { } else if (base_script->get_constants().has(subclass)) {
Ref<GDScript> new_base_class = base_script->get_constants()[subclass]; Ref<GDScript> new_base_class = base_script->get_constants()[subclass];
@ -5255,7 +5256,7 @@ void GDScriptParser::_determine_inheritance(ClassNode *p_class) {
_set_error("Constant is not a class: " + ident, p_class->line); _set_error("Constant is not a class: " + ident, p_class->line);
return; return;
} }
base_script = new_base_class; find_subclass = new_base_class;
} else { } else {
_set_error("Could not find subclass: " + ident, p_class->line); _set_error("Could not find subclass: " + ident, p_class->line);
@ -5263,7 +5264,7 @@ void GDScriptParser::_determine_inheritance(ClassNode *p_class) {
} }
} }
script = base_script; script = find_subclass;
} else if (!base_class) { } else if (!base_class) {
@ -7661,6 +7662,11 @@ void GDScriptParser::_check_function_types(FunctionNode *p_function) {
if (p_function->arguments_usage[i] == 0 && !p_function->arguments[i].operator String().begins_with("_")) { if (p_function->arguments_usage[i] == 0 && !p_function->arguments[i].operator String().begins_with("_")) {
_add_warning(GDScriptWarning::UNUSED_ARGUMENT, p_function->line, p_function->name, p_function->arguments[i].operator String()); _add_warning(GDScriptWarning::UNUSED_ARGUMENT, p_function->line, p_function->name, p_function->arguments[i].operator String());
} }
for (int j = 0; j < current_class->variables.size(); j++) {
if (current_class->variables[j].identifier == p_function->arguments[i]) {
_add_warning(GDScriptWarning::SHADOWED_VARIABLE, p_function->line, p_function->arguments[i], itos(current_class->variables[j].line));
}
}
#endif // DEBUG_ENABLED #endif // DEBUG_ENABLED
} }
@ -7734,6 +7740,17 @@ void GDScriptParser::_check_function_types(FunctionNode *p_function) {
p_function->return_type.has_type = false; p_function->return_type.has_type = false;
p_function->return_type.may_yield = true; p_function->return_type.may_yield = true;
} }
#ifdef DEBUG_ENABLED
for (Map<StringName, LocalVarNode *>::Element *E = p_function->body->variables.front(); E; E = E->next()) {
LocalVarNode *lv = E->get();
for (int i = 0; i < current_class->variables.size(); i++) {
if (current_class->variables[i].identifier == lv->name) {
_add_warning(GDScriptWarning::SHADOWED_VARIABLE, lv->line, lv->name, itos(current_class->variables[i].line));
}
}
}
#endif // DEBUG_ENABLED
} }
void GDScriptParser::_check_class_blocks_types(ClassNode *p_class) { void GDScriptParser::_check_class_blocks_types(ClassNode *p_class) {
@ -8163,6 +8180,9 @@ void GDScriptParser::_add_warning(int p_code, int p_line, const String &p_symbol
} }
void GDScriptParser::_add_warning(int p_code, int p_line, const Vector<String> &p_symbols) { void GDScriptParser::_add_warning(int p_code, int p_line, const Vector<String> &p_symbols) {
if (GLOBAL_GET("debug/gdscript/warnings/exclude_addons").booleanize() && base_path.begins_with("res://addons/")) {
return;
}
if (tokenizer->is_ignoring_warnings() || !GLOBAL_GET("debug/gdscript/warnings/enable").booleanize()) { if (tokenizer->is_ignoring_warnings() || !GLOBAL_GET("debug/gdscript/warnings/enable").booleanize()) {
return; return;
} }

View file

@ -120,8 +120,8 @@ def configure(env):
else: else:
env.Append(LINKFLAGS=os.path.join(mono_lib_path, mono_static_lib_name + lib_suffix)) env.Append(LINKFLAGS=os.path.join(mono_lib_path, mono_static_lib_name + lib_suffix))
env.Append(LIBS='psapi') env.Append(LIBS=['psapi'])
env.Append(LIBS='version') env.Append(LIBS=['version'])
else: else:
mono_lib_name = find_file_in_dir(mono_lib_path, mono_lib_names, extension='.lib') mono_lib_name = find_file_in_dir(mono_lib_path, mono_lib_names, extension='.lib')
@ -131,7 +131,7 @@ def configure(env):
if env.msvc: if env.msvc:
env.Append(LINKFLAGS=mono_lib_name + Environment()['LIBSUFFIX']) env.Append(LINKFLAGS=mono_lib_name + Environment()['LIBSUFFIX'])
else: else:
env.Append(LIBS=mono_lib_name) env.Append(LIBS=[mono_lib_name])
mono_bin_path = os.path.join(mono_root, 'bin') mono_bin_path = os.path.join(mono_root, 'bin')

View file

@ -919,7 +919,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
} }
#endif #endif
void CSharpLanguage::project_assembly_loaded() { void CSharpLanguage::_load_scripts_metadata() {
scripts_metadata.clear(); scripts_metadata.clear();
@ -953,6 +953,7 @@ void CSharpLanguage::project_assembly_loaded() {
} }
scripts_metadata = old_dict_var.operator Dictionary(); scripts_metadata = old_dict_var.operator Dictionary();
scripts_metadata_invalidated = false;
print_verbose("Successfully loaded scripts metadata"); print_verbose("Successfully loaded scripts metadata");
} else { } else {
@ -1024,11 +1025,13 @@ bool CSharpLanguage::debug_break(const String &p_error, bool p_allow_continue) {
} }
} }
void CSharpLanguage::_uninitialize_script_bindings() { void CSharpLanguage::_on_scripts_domain_unloaded() {
for (Map<Object *, CSharpScriptBinding>::Element *E = script_bindings.front(); E; E = E->next()) { for (Map<Object *, CSharpScriptBinding>::Element *E = script_bindings.front(); E; E = E->next()) {
CSharpScriptBinding &script_binding = E->value(); CSharpScriptBinding &script_binding = E->value();
script_binding.inited = false; script_binding.inited = false;
} }
scripts_metadata_invalidated = true;
} }
void CSharpLanguage::set_language_index(int p_idx) { void CSharpLanguage::set_language_index(int p_idx) {
@ -1086,6 +1089,8 @@ CSharpLanguage::CSharpLanguage() {
#endif #endif
lang_idx = -1; lang_idx = -1;
scripts_metadata_invalidated = true;
} }
CSharpLanguage::~CSharpLanguage() { CSharpLanguage::~CSharpLanguage() {

View file

@ -309,14 +309,17 @@ class CSharpLanguage : public ScriptLanguage {
int lang_idx; int lang_idx;
Dictionary scripts_metadata; Dictionary scripts_metadata;
bool scripts_metadata_invalidated;
// For debug_break and debug_break_parse // For debug_break and debug_break_parse
int _debug_parse_err_line; int _debug_parse_err_line;
String _debug_parse_err_file; String _debug_parse_err_file;
String _debug_error; String _debug_error;
void _load_scripts_metadata();
friend class GDMono; friend class GDMono;
void _uninitialize_script_bindings(); void _on_scripts_domain_unloaded();
public: public:
StringNameCache string_names; StringNameCache string_names;
@ -341,9 +344,15 @@ public:
void reload_assemblies(bool p_soft_reload); void reload_assemblies(bool p_soft_reload);
#endif #endif
void project_assembly_loaded(); _FORCE_INLINE_ Dictionary get_scripts_metadata_or_nothing() {
return scripts_metadata_invalidated ? Dictionary() : scripts_metadata;
}
_FORCE_INLINE_ const Dictionary &get_scripts_metadata() { return scripts_metadata; } _FORCE_INLINE_ const Dictionary &get_scripts_metadata() {
if (scripts_metadata_invalidated)
_load_scripts_metadata();
return scripts_metadata;
}
virtual String get_name() const; virtual String get_name() const;

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?> <?xml version="1.0" encoding="UTF-8" ?>
<class name="@C#" category="Core" version="3.1.1"> <class name="@C#" category="Core" version="3.1.2">
<brief_description> <brief_description>
</brief_description> </brief_description>
<description> <description>

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?> <?xml version="1.0" encoding="UTF-8" ?>
<class name="CSharpScript" inherits="Script" category="Core" version="3.1.1"> <class name="CSharpScript" inherits="Script" category="Core" version="3.1.2">
<brief_description> <brief_description>
</brief_description> </brief_description>
<description> <description>

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?> <?xml version="1.0" encoding="UTF-8" ?>
<class name="GodotSharp" inherits="Object" category="Core" version="3.1.1"> <class name="GodotSharp" inherits="Object" category="Core" version="3.1.2">
<brief_description> <brief_description>
</brief_description> </brief_description>
<description> <description>

View file

@ -158,7 +158,7 @@ Error generate_scripts_metadata(const String &p_project_path, const String &p_ou
PoolStringArray project_files = GDMonoMarshal::mono_array_to_PoolStringArray(ret); PoolStringArray project_files = GDMonoMarshal::mono_array_to_PoolStringArray(ret);
PoolStringArray::Read r = project_files.read(); PoolStringArray::Read r = project_files.read();
Dictionary old_dict = CSharpLanguage::get_singleton()->get_scripts_metadata(); Dictionary old_dict = CSharpLanguage::get_singleton()->get_scripts_metadata_or_nothing();
Dictionary new_dict; Dictionary new_dict;
for (int i = 0; i < project_files.size(); i++) { for (int i = 0; i < project_files.size(); i++) {

View file

@ -121,25 +121,28 @@ void gdmono_debug_init() {
mono_debug_init(MONO_DEBUG_FORMAT_MONO); mono_debug_init(MONO_DEBUG_FORMAT_MONO);
CharString da_args = OS::get_singleton()->get_environment("GODOT_MONO_DEBUGGER_AGENT").utf8();
#ifdef TOOLS_ENABLED
int da_port = GLOBAL_DEF("mono/debugger_agent/port", 23685); int da_port = GLOBAL_DEF("mono/debugger_agent/port", 23685);
bool da_suspend = GLOBAL_DEF("mono/debugger_agent/wait_for_debugger", false); bool da_suspend = GLOBAL_DEF("mono/debugger_agent/wait_for_debugger", false);
int da_timeout = GLOBAL_DEF("mono/debugger_agent/wait_timeout", 3000); int da_timeout = GLOBAL_DEF("mono/debugger_agent/wait_timeout", 3000);
#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint() || if (Engine::get_singleton()->is_editor_hint() ||
ProjectSettings::get_singleton()->get_resource_path().empty() || ProjectSettings::get_singleton()->get_resource_path().empty() ||
Main::is_project_manager()) { Main::is_project_manager()) {
return; return;
} }
#endif
CharString da_args = OS::get_singleton()->get_environment("GODOT_MONO_DEBUGGER_AGENT").utf8();
if (da_args.length() == 0) { if (da_args.length() == 0) {
da_args = String("--debugger-agent=transport=dt_socket,address=127.0.0.1:" + itos(da_port) + da_args = String("--debugger-agent=transport=dt_socket,address=127.0.0.1:" + itos(da_port) +
",embedding=1,server=y,suspend=" + (da_suspend ? "y,timeout=" + itos(da_timeout) : "n")) ",embedding=1,server=y,suspend=" + (da_suspend ? "y,timeout=" + itos(da_timeout) : "n"))
.utf8(); .utf8();
} }
#else
if (da_args.length() == 0)
return; // Exported games don't use the project settings to setup the debugger agent
#endif
// --debugger-agent=help // --debugger-agent=help
const char *options[] = { const char *options[] = {
@ -665,8 +668,6 @@ bool GDMono::_load_project_assembly() {
if (success) { if (success) {
mono_assembly_set_main(project_assembly->get_assembly()); mono_assembly_set_main(project_assembly->get_assembly());
CSharpLanguage::get_singleton()->project_assembly_loaded();
} else { } else {
if (OS::get_singleton()->is_stdout_verbose()) if (OS::get_singleton()->is_stdout_verbose())
print_error("Mono: Failed to load project assembly"); print_error("Mono: Failed to load project assembly");
@ -873,7 +874,7 @@ Error GDMono::reload_scripts_domain() {
} }
} }
CSharpLanguage::get_singleton()->_uninitialize_script_bindings(); CSharpLanguage::get_singleton()->_on_scripts_domain_unloaded();
Error err = _load_scripts_domain(); Error err = _load_scripts_domain();
if (err != OK) { if (err != OK) {

View file

@ -33,6 +33,7 @@ if env['builtin_pcre2']:
"pcre2_newline.c", "pcre2_newline.c",
"pcre2_ord2utf.c", "pcre2_ord2utf.c",
"pcre2_pattern_info.c", "pcre2_pattern_info.c",
"pcre2_script_run.c",
"pcre2_serialize.c", "pcre2_serialize.c",
"pcre2_string_utils.c", "pcre2_string_utils.c",
"pcre2_study.c", "pcre2_study.c",

View file

@ -266,8 +266,8 @@ void AudioStreamOGGVorbis::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_loop_offset"), &AudioStreamOGGVorbis::get_loop_offset); ClassDB::bind_method(D_METHOD("get_loop_offset"), &AudioStreamOGGVorbis::get_loop_offset);
ADD_PROPERTY(PropertyInfo(Variant::POOL_BYTE_ARRAY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_data", "get_data"); ADD_PROPERTY(PropertyInfo(Variant::POOL_BYTE_ARRAY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_data", "get_data");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "loop", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_loop", "has_loop"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "loop"), "set_loop", "has_loop");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "loop_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_loop_offset", "get_loop_offset"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "loop_offset"), "set_loop_offset", "get_loop_offset");
} }
AudioStreamOGGVorbis::AudioStreamOGGVorbis() { AudioStreamOGGVorbis::AudioStreamOGGVorbis() {

View file

@ -23,10 +23,11 @@ if env['builtin_miniupnpc']:
"portlistingparse.c", "portlistingparse.c",
"upnpreplyparse.c", "upnpreplyparse.c",
] ]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] thirdparty_sources = [thirdparty_dir + "miniupnpc/" + file for file in thirdparty_sources]
env_upnp.Append(CPPPATH=[thirdparty_dir]) env_upnp.Append(CPPPATH=[thirdparty_dir])
env_upnp.Append(CPPFLAGS=["-DMINIUPNP_STATICLIB"]) env_upnp.Append(CPPFLAGS=["-DMINIUPNP_STATICLIB"])
env_upnp.Append(CPPFLAGS=["-DMINIUPNPC_SET_SOCKET_TIMEOUT"])
env_thirdparty = env_upnp.Clone() env_thirdparty = env_upnp.Clone()
env_thirdparty.disable_warnings() env_thirdparty.disable_warnings()

View file

@ -45,15 +45,7 @@ bool VisualScriptNode::is_breakpoint() const {
return breakpoint; return breakpoint;
} }
void VisualScriptNode::_notification(int p_what) {
if (p_what == NOTIFICATION_POSTINITIALIZE) {
validate_input_default_values();
}
}
void VisualScriptNode::ports_changed_notify() { void VisualScriptNode::ports_changed_notify() {
validate_input_default_values();
emit_signal("ports_changed"); emit_signal("ports_changed");
} }
@ -272,11 +264,7 @@ void VisualScript::_node_ports_changed(int p_id) {
Function &func = functions[function]; Function &func = functions[function];
Ref<VisualScriptNode> vsn = func.nodes[p_id].node; Ref<VisualScriptNode> vsn = func.nodes[p_id].node;
if (OS::get_singleton()->get_main_loop() && vsn->validate_input_default_values();
Object::cast_to<SceneTree>(OS::get_singleton()->get_main_loop()) &&
Engine::get_singleton()->is_editor_hint()) {
vsn->validate_input_default_values(); //force validate default values when editing on editor
}
//must revalidate all the functions //must revalidate all the functions
@ -352,6 +340,7 @@ void VisualScript::add_node(const StringName &p_func, int p_id, const Ref<Visual
Ref<VisualScriptNode> vsn = p_node; Ref<VisualScriptNode> vsn = p_node;
vsn->connect("ports_changed", this, "_node_ports_changed", varray(p_id)); vsn->connect("ports_changed", this, "_node_ports_changed", varray(p_id));
vsn->scripts_used.insert(this); vsn->scripts_used.insert(this);
vsn->validate_input_default_values(); // Validate when fully loaded
func.nodes[p_id] = nd; func.nodes[p_id] = nd;
} }

View file

@ -54,7 +54,6 @@ class VisualScriptNode : public Resource {
void validate_input_default_values(); void validate_input_default_values();
protected: protected:
void _notification(int p_what);
void ports_changed_notify(); void ports_changed_notify();
static void _bind_methods(); static void _bind_methods();

View file

@ -2040,7 +2040,7 @@ void VisualScriptEditor::set_edit_state(const Variant &p_state) {
Dictionary d = p_state; Dictionary d = p_state;
if (d.has("function")) { if (d.has("function")) {
edited_func = p_state; edited_func = d["function"];
selected = edited_func; selected = edited_func;
} }

View file

@ -28,4 +28,4 @@ with open_utf8('register_platform_apis.gen.cpp', 'w') as f:
platform_sources.append('register_platform_apis.gen.cpp') platform_sources.append('register_platform_apis.gen.cpp')
lib = env.add_library('platform', platform_sources) lib = env.add_library('platform', platform_sources)
env.Prepend(LIBS=lib) env.Prepend(LIBS=[lib])

View file

@ -5,7 +5,7 @@ buildscript {
$$GRADLE_REPOSITORY_URLS$$ $$GRADLE_REPOSITORY_URLS$$
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.2.1' classpath 'com.android.tools.build:gradle:3.4.2'
$$GRADLE_CLASSPATH$$ $$GRADLE_CLASSPATH$$
} }
} }

View file

@ -1,5 +1,7 @@
# Third party libraries # Third-party libraries
This file list third-party libraries used in the Android source folder,
with their provenance and, when relevant, modifications made to those files.
## Google's vending library ## Google's vending library
@ -7,12 +9,13 @@
- Version: git (eb57657, 2018) with modifications - Version: git (eb57657, 2018) with modifications
- License: Apache 2.0 - License: Apache 2.0
Overwrite all files under `com/google/android/vending` Overwrite all files under `com/google/android/vending`.
### Modify some files to avoid compile error and lint warning Modify those files to avoid compile error and lint warning:
#### com/google/android/vending/licensing/util/Base64.java - `com/google/android/vending/licensing/util/Base64.java`
```
```diff
@@ -338,7 +338,8 @@ public class Base64 { @@ -338,7 +338,8 @@ public class Base64 {
e += 4; e += 4;
} }
@ -24,8 +27,9 @@ Overwrite all files under `com/google/android/vending`
} }
``` ```
#### com/google/android/vending/licensing/LicenseChecker.java - `com/google/android/vending/licensing/LicenseChecker.java`
```
```diff
@@ -29,8 +29,8 @@ import android.os.RemoteException; @@ -29,8 +29,8 @@ import android.os.RemoteException;
import android.provider.Settings.Secure; import android.provider.Settings.Secure;
import android.util.Log; import android.util.Log;
@ -37,11 +41,3 @@ Overwrite all files under `com/google/android/vending`
import com.google.android.vending.licensing.util.Base64; import com.google.android.vending.licensing.util.Base64;
import com.google.android.vending.licensing.util.Base64DecoderException; import com.google.android.vending.licensing.util.Base64DecoderException;
``` ```
```
@@ -287,13 +287,15 @@ public class LicenseChecker implements ServiceConnection {
if (logResponse) {
- String android_id = Secure.getString(mContext.getContentResolver(),
- Secure.ANDROID_ID);
+ String android_id = Secure.ANDROID_ID;
Date date = new Date();
```

View file

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View file

@ -746,7 +746,8 @@ public abstract class DownloaderService extends CustomIntentService implements I
public void run() { public void run() {
setServiceRunning(true); setServiceRunning(true);
mNotification.onDownloadStateChanged(IDownloaderClient.STATE_FETCHING_URL); mNotification.onDownloadStateChanged(IDownloaderClient.STATE_FETCHING_URL);
String deviceId = Secure.ANDROID_ID; String deviceId = Secure.getString(mContext.getContentResolver(),
Secure.ANDROID_ID);
final APKExpansionPolicy aep = new APKExpansionPolicy(mContext, final APKExpansionPolicy aep = new APKExpansionPolicy(mContext,
new AESObfuscator(getSALT(), mContext.getPackageName(), deviceId)); new AESObfuscator(getSALT(), mContext.getPackageName(), deviceId));

View file

@ -287,7 +287,8 @@ public class LicenseChecker implements ServiceConnection {
} }
if (logResponse) { if (logResponse) {
String android_id = Secure.ANDROID_ID; String android_id = Secure.getString(mContext.getContentResolver(),
Secure.ANDROID_ID);
Date date = new Date(); Date date = new Date();
Log.d(TAG, "Server Failure: " + stringError); Log.d(TAG, "Server Failure: " + stringError);
Log.d(TAG, "Android ID: " + android_id); Log.d(TAG, "Android ID: " + android_id);

View file

@ -287,14 +287,6 @@ bool OS_Android::can_draw() const {
return true; //always? return true; //always?
} }
void OS_Android::set_cursor_shape(CursorShape p_shape) {
//android really really really has no mouse.. how amazing..
}
void OS_Android::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
}
void OS_Android::main_loop_begin() { void OS_Android::main_loop_begin() {
if (main_loop) if (main_loop)

View file

@ -187,9 +187,6 @@ public:
virtual bool can_draw() const; virtual bool can_draw() const;
virtual void set_cursor_shape(CursorShape p_shape);
virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
void main_loop_begin(); void main_loop_begin();
bool main_loop_iterate(); bool main_loop_iterate();
void main_loop_request_go_back(); void main_loop_request_go_back();

View file

@ -203,6 +203,10 @@ void OS_Haiku::set_cursor_shape(CursorShape p_shape) {
//ERR_PRINT("set_cursor_shape() NOT IMPLEMENTED"); //ERR_PRINT("set_cursor_shape() NOT IMPLEMENTED");
} }
OS::CursorShape OS_Haiku::get_cursor_shape() const {
// TODO: implement get_cursor_shape
}
void OS_Haiku::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { void OS_Haiku::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
// TODO // TODO
} }

View file

@ -86,6 +86,7 @@ public:
virtual Point2 get_mouse_position() const; virtual Point2 get_mouse_position() const;
virtual int get_mouse_button_state() const; virtual int get_mouse_button_state() const;
virtual void set_cursor_shape(CursorShape p_shape); virtual void set_cursor_shape(CursorShape p_shape);
virtual CursorShape get_cursor_shape() const;
virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot); virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
virtual int get_screen_count() const; virtual int get_screen_count() const;

View file

@ -491,17 +491,11 @@ void OSIPhone::set_keep_screen_on(bool p_enabled) {
_set_keep_screen_on(p_enabled); _set_keep_screen_on(p_enabled);
}; };
void OSIPhone::set_cursor_shape(CursorShape p_shape){
};
String OSIPhone::get_user_data_dir() const { String OSIPhone::get_user_data_dir() const {
return data_dir; return data_dir;
}; };
void OSIPhone::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot){};
String OSIPhone::get_name() { String OSIPhone::get_name() {
return "iOS"; return "iOS";

View file

@ -167,9 +167,6 @@ public:
virtual void hide_virtual_keyboard(); virtual void hide_virtual_keyboard();
virtual int get_virtual_keyboard_height() const; virtual int get_virtual_keyboard_height() const;
virtual void set_cursor_shape(CursorShape p_shape);
virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
virtual Size2 get_window_size() const; virtual Size2 get_window_size() const;
virtual Rect2 get_window_safe_area() const; virtual Rect2 get_window_safe_area() const;

View file

@ -39,6 +39,10 @@
- (void)didReceiveMemoryWarning; - (void)didReceiveMemoryWarning;
- (void)viewDidLoad;
- (UIRectEdge)preferredScreenEdgesDeferringSystemGestures;
- (BOOL)prefersStatusBarHidden; - (BOOL)prefersStatusBarHidden;
@end @end

View file

@ -83,6 +83,18 @@ int add_cmdline(int p_argc, char **p_args) {
printf("*********** did receive memory warning!\n"); printf("*********** did receive memory warning!\n");
}; };
- (void)viewDidLoad {
[super viewDidLoad];
if (@available(iOS 11.0, *)) {
[self setNeedsUpdateOfScreenEdgesDeferringSystemGestures];
}
}
- (UIRectEdge)preferredScreenEdgesDeferringSystemGestures {
return UIRectEdgeAll;
}
- (BOOL)shouldAutorotate { - (BOOL)shouldAutorotate {
switch (OS::get_singleton()->get_screen_orientation()) { switch (OS::get_singleton()->get_screen_orientation()) {
case OS::SCREEN_SENSOR: case OS::SCREEN_SENSOR:

View file

@ -70,6 +70,20 @@ static bool is_canvas_focused() {
/* clang-format on */ /* clang-format on */
} }
static Point2 correct_canvas_position(int x, int y) {
int canvas_width;
int canvas_height;
emscripten_get_canvas_element_size(NULL, &canvas_width, &canvas_height);
double element_width;
double element_height;
emscripten_get_element_css_size(NULL, &element_width, &element_height);
x = (int)(canvas_width / element_width * x);
y = (int)(canvas_height / element_height * y);
return Point2(x, y);
}
static bool cursor_inside_canvas = true; static bool cursor_inside_canvas = true;
EM_BOOL OS_JavaScript::fullscreen_change_callback(int p_event_type, const EmscriptenFullscreenChangeEvent *p_event, void *p_user_data) { EM_BOOL OS_JavaScript::fullscreen_change_callback(int p_event_type, const EmscriptenFullscreenChangeEvent *p_event, void *p_user_data) {
@ -285,7 +299,7 @@ EM_BOOL OS_JavaScript::mouse_button_callback(int p_event_type, const EmscriptenM
Ref<InputEventMouseButton> ev; Ref<InputEventMouseButton> ev;
ev.instance(); ev.instance();
ev->set_pressed(p_event_type == EMSCRIPTEN_EVENT_MOUSEDOWN); ev->set_pressed(p_event_type == EMSCRIPTEN_EVENT_MOUSEDOWN);
ev->set_position(Point2(p_event->canvasX, p_event->canvasY)); ev->set_position(correct_canvas_position(p_event->canvasX, p_event->canvasY));
ev->set_global_position(ev->get_position()); ev->set_global_position(ev->get_position());
dom2godot_mod(p_event, ev); dom2godot_mod(p_event, ev);
switch (p_event->button) { switch (p_event->button) {
@ -349,7 +363,7 @@ EM_BOOL OS_JavaScript::mousemove_callback(int p_event_type, const EmscriptenMous
OS_JavaScript *os = get_singleton(); OS_JavaScript *os = get_singleton();
int input_mask = os->input->get_mouse_button_mask(); int input_mask = os->input->get_mouse_button_mask();
Point2 pos = Point2(p_event->canvasX, p_event->canvasY); Point2 pos = correct_canvas_position(p_event->canvasX, p_event->canvasY);
// For motion outside the canvas, only read mouse movement if dragging // For motion outside the canvas, only read mouse movement if dragging
// started inside the canvas; imitating desktop app behaviour. // started inside the canvas; imitating desktop app behaviour.
if (!cursor_inside_canvas && !input_mask) if (!cursor_inside_canvas && !input_mask)
@ -666,7 +680,7 @@ EM_BOOL OS_JavaScript::touch_press_callback(int p_event_type, const EmscriptenTo
if (!touch.isChanged) if (!touch.isChanged)
continue; continue;
ev->set_index(touch.identifier); ev->set_index(touch.identifier);
ev->set_position(Point2(touch.canvasX, touch.canvasY)); ev->set_position(correct_canvas_position(touch.canvasX, touch.canvasY));
os->touches[i] = ev->get_position(); os->touches[i] = ev->get_position();
ev->set_pressed(p_event_type == EMSCRIPTEN_EVENT_TOUCHSTART); ev->set_pressed(p_event_type == EMSCRIPTEN_EVENT_TOUCHSTART);
@ -691,7 +705,7 @@ EM_BOOL OS_JavaScript::touchmove_callback(int p_event_type, const EmscriptenTouc
if (!touch.isChanged) if (!touch.isChanged)
continue; continue;
ev->set_index(touch.identifier); ev->set_index(touch.identifier);
ev->set_position(Point2(touch.canvasX, touch.canvasY)); ev->set_position(correct_canvas_position(touch.canvasX, touch.canvasY));
Point2 &prev = os->touches[i]; Point2 &prev = os->touches[i];
ev->set_relative(ev->get_position() - prev); ev->set_relative(ev->get_position() - prev);
prev = ev->get_position(); prev = ev->get_position();

View file

@ -172,6 +172,7 @@ public:
virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false); virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false);
virtual void set_cursor_shape(CursorShape p_shape); virtual void set_cursor_shape(CursorShape p_shape);
virtual CursorShape get_cursor_shape() const;
virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot); virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
virtual void set_mouse_show(bool p_show); virtual void set_mouse_show(bool p_show);

View file

@ -714,8 +714,6 @@ static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) {
if (OS_OSX::singleton->main_loop && OS_OSX::singleton->mouse_mode != OS::MOUSE_MODE_CAPTURED) if (OS_OSX::singleton->main_loop && OS_OSX::singleton->mouse_mode != OS::MOUSE_MODE_CAPTURED)
OS_OSX::singleton->main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_EXIT); OS_OSX::singleton->main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_EXIT);
if (OS_OSX::singleton->input)
OS_OSX::singleton->input->set_mouse_in_window(false);
} }
- (void)mouseEntered:(NSEvent *)event { - (void)mouseEntered:(NSEvent *)event {
@ -723,8 +721,6 @@ static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) {
return; return;
if (OS_OSX::singleton->main_loop && OS_OSX::singleton->mouse_mode != OS::MOUSE_MODE_CAPTURED) if (OS_OSX::singleton->main_loop && OS_OSX::singleton->mouse_mode != OS::MOUSE_MODE_CAPTURED)
OS_OSX::singleton->main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_ENTER); OS_OSX::singleton->main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_ENTER);
if (OS_OSX::singleton->input)
OS_OSX::singleton->input->set_mouse_in_window(true);
OS::CursorShape p_shape = OS_OSX::singleton->cursor_shape; OS::CursorShape p_shape = OS_OSX::singleton->cursor_shape;
OS_OSX::singleton->cursor_shape = OS::CURSOR_MAX; OS_OSX::singleton->cursor_shape = OS::CURSOR_MAX;
@ -1700,6 +1696,11 @@ void OS_OSX::set_cursor_shape(CursorShape p_shape) {
cursor_shape = p_shape; cursor_shape = p_shape;
} }
OS::CursorShape OS_OSX::get_cursor_shape() const {
return cursor_shape;
}
void OS_OSX::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { void OS_OSX::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
if (p_cursor.is_valid()) { if (p_cursor.is_valid()) {
Ref<Texture> texture = p_cursor; Ref<Texture> texture = p_cursor;

Some files were not shown because too many files have changed in this diff Show more