Merge pull request from akien-mga/3.2-cherrypicks

Cherry-picks for the 3.2 branch (future 3.2.4) - 26th batch
This commit is contained in:
Rémi Verschelde 2021-03-02 12:02:47 +01:00 committed by GitHub
commit 08898e97a4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 104 additions and 25 deletions

View File

@ -54,6 +54,12 @@ bool Logger::should_log(bool p_err) {
return (!p_err || _print_error_enabled) && (p_err || _print_line_enabled); return (!p_err || _print_error_enabled) && (p_err || _print_line_enabled);
} }
bool Logger::_flush_stdout_on_print = true;
void Logger::set_flush_stdout_on_print(bool value) {
_flush_stdout_on_print = value;
}
void Logger::log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type) { void Logger::log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type) {
if (!should_log(true)) { if (!should_log(true)) {
return; return;
@ -210,7 +216,7 @@ void RotatedFileLogger::logv(const char *p_format, va_list p_list, bool p_err) {
Memory::free_static(buf); Memory::free_static(buf);
} }
if (p_err || !ProjectSettings::get_singleton() || GLOBAL_GET("application/run/flush_stdout_on_print")) { if (p_err || _flush_stdout_on_print) {
// Don't always flush when printing stdout to avoid performance // Don't always flush when printing stdout to avoid performance
// issues when `print()` is spammed in release builds. // issues when `print()` is spammed in release builds.
file->flush(); file->flush();
@ -231,7 +237,7 @@ void StdLogger::logv(const char *p_format, va_list p_list, bool p_err) {
vfprintf(stderr, p_format, p_list); vfprintf(stderr, p_format, p_list);
} else { } else {
vprintf(p_format, p_list); vprintf(p_format, p_list);
if (!ProjectSettings::get_singleton() || GLOBAL_GET("application/run/flush_stdout_on_print")) { if (_flush_stdout_on_print) {
// Don't always flush when printing stdout to avoid performance // Don't always flush when printing stdout to avoid performance
// issues when `print()` is spammed in release builds. // issues when `print()` is spammed in release builds.
fflush(stdout); fflush(stdout);

View File

@ -41,6 +41,8 @@ class Logger {
protected: protected:
bool should_log(bool p_err); bool should_log(bool p_err);
static bool _flush_stdout_on_print;
public: public:
enum ErrorType { enum ErrorType {
ERR_ERROR, ERR_ERROR,
@ -49,6 +51,8 @@ public:
ERR_SHADER ERR_SHADER
}; };
static void set_flush_stdout_on_print(bool value);
virtual void logv(const char *p_format, va_list p_list, bool p_err) _PRINTF_FORMAT_ATTRIBUTE_2_0 = 0; virtual void logv(const char *p_format, va_list p_list, bool p_err) _PRINTF_FORMAT_ATTRIBUTE_2_0 = 0;
virtual void log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type = ERR_ERROR); virtual void log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type = ERR_ERROR);

View File

@ -63,7 +63,7 @@
<argument index="0" name="to_point" type="Vector2"> <argument index="0" name="to_point" type="Vector2">
</argument> </argument>
<description> <description>
Returns the closest point (in curve's local space) to [code]to_point[/code]. Returns the closest baked point (in curve's local space) to [code]to_point[/code].
[code]to_point[/code] must be in this curve's local space. [code]to_point[/code] must be in this curve's local space.
</description> </description>
</method> </method>

View File

@ -78,7 +78,7 @@
<argument index="0" name="to_point" type="Vector3"> <argument index="0" name="to_point" type="Vector3">
</argument> </argument>
<description> <description>
Returns the closest point (in curve's local space) to [code]to_point[/code]. Returns the closest baked point (in curve's local space) to [code]to_point[/code].
[code]to_point[/code] must be in this curve's local space. [code]to_point[/code] must be in this curve's local space.
</description> </description>
</method> </method>

View File

@ -252,9 +252,11 @@
If [code]true[/code], flushes the standard output stream every time a line is printed. This affects both terminal logging and file logging. If [code]true[/code], flushes the standard output stream every time a line is printed. This affects both terminal logging and file logging.
When running a project, this setting must be enabled if you want logs to be collected by service managers such as systemd/journalctl. This setting is disabled by default on release builds, since flushing on every printed line will negatively affect performance if lots of lines are printed in a rapid succession. Also, if this setting is enabled, logged files will still be written successfully if the application crashes or is otherwise killed by the user (without being closed "normally"). When running a project, this setting must be enabled if you want logs to be collected by service managers such as systemd/journalctl. This setting is disabled by default on release builds, since flushing on every printed line will negatively affect performance if lots of lines are printed in a rapid succession. Also, if this setting is enabled, logged files will still be written successfully if the application crashes or is otherwise killed by the user (without being closed "normally").
[b]Note:[/b] Regardless of this setting, the standard error stream ([code]stderr[/code]) is always flushed when a line is printed to it. [b]Note:[/b] Regardless of this setting, the standard error stream ([code]stderr[/code]) is always flushed when a line is printed to it.
Changes to this setting will only be applied upon restarting the application.
</member> </member>
<member name="application/run/flush_stdout_on_print.debug" type="bool" setter="" getter="" default="true"> <member name="application/run/flush_stdout_on_print.debug" type="bool" setter="" getter="" default="true">
Debug build override for [member application/run/flush_stdout_on_print], as performance is less important during debugging. Debug build override for [member application/run/flush_stdout_on_print], as performance is less important during debugging.
Changes to this setting will only be applied upon restarting the application.
</member> </member>
<member name="application/run/frame_delay_msec" type="int" setter="" getter="" default="0"> <member name="application/run/frame_delay_msec" type="int" setter="" getter="" default="0">
Forces a delay between frames in the main loop (in milliseconds). This may be useful if you plan to disable vertical synchronization. Forces a delay between frames in the main loop (in milliseconds). This may be useful if you plan to disable vertical synchronization.

View File

@ -4,12 +4,12 @@
Customizable [StyleBox] with a given set of parameters (no texture required). Customizable [StyleBox] with a given set of parameters (no texture required).
</brief_description> </brief_description>
<description> <description>
This [StyleBox] can be used to achieve all kinds of looks without the need of a texture. Those properties are customizable: This [StyleBox] can be used to achieve all kinds of looks without the need of a texture. The following properties are customizable:
- Color - Color
- Border width (individual width for each border) - Border width (individual width for each border)
- Rounded corners (individual radius for each corner) - Rounded corners (individual radius for each corner)
- Shadow (with blur and offset) - Shadow (with blur and offset)
Setting corner radius to high values is allowed. As soon as corners would overlap, the stylebox will switch to a relative system. Example: Setting corner radius to high values is allowed. As soon as corners overlap, the stylebox will switch to a relative system. Example:
[codeblock] [codeblock]
height = 30 height = 30
corner_radius_top_left = 50 corner_radius_top_left = 50
@ -178,8 +178,8 @@
Border width for the top border. Border width for the top border.
</member> </member>
<member name="corner_detail" type="int" setter="set_corner_detail" getter="get_corner_detail" default="8"> <member name="corner_detail" type="int" setter="set_corner_detail" getter="get_corner_detail" default="8">
This sets the amount of vertices used for each corner. Higher values result in rounder corners but take more processing power to compute. When choosing a value, you should take the corner radius ([method set_corner_radius_all]) into account. This sets the number of vertices used for each corner. Higher values result in rounder corners but take more processing power to compute. When choosing a value, you should take the corner radius ([method set_corner_radius_all]) into account.
For corner radii smaller than 10, [code]4[/code] or [code]5[/code] should be enough. For corner radii smaller than 30, values between [code]8[/code] and [code]12[/code] should be enough. For corner radii less than 10, [code]4[/code] or [code]5[/code] should be enough. For corner radii less than 30, values between [code]8[/code] and [code]12[/code] should be enough.
A corner detail of [code]1[/code] will result in chamfered corners instead of rounded corners, which is useful for some artistic effects. A corner detail of [code]1[/code] will result in chamfered corners instead of rounded corners, which is useful for some artistic effects.
</member> </member>
<member name="corner_radius_bottom_left" type="int" setter="set_corner_radius" getter="get_corner_radius" default="0"> <member name="corner_radius_bottom_left" type="int" setter="set_corner_radius" getter="get_corner_radius" default="0">

View File

@ -818,7 +818,8 @@ void EditorNode::_scan_external_changes() {
// Check if any edited scene has changed. // Check if any edited scene has changed.
for (int i = 0; i < editor_data.get_edited_scene_count(); i++) { for (int i = 0; i < editor_data.get_edited_scene_count(); i++) {
if (editor_data.get_scene_path(i) == "") { DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
if (editor_data.get_scene_path(i) == "" || !da->file_exists(editor_data.get_scene_path(i))) {
continue; continue;
} }

View File

@ -1820,8 +1820,10 @@ void TileMapEditor::edit(Node *p_tile_map) {
canvas_item_editor_viewport = CanvasItemEditor::get_singleton()->get_viewport_control(); canvas_item_editor_viewport = CanvasItemEditor::get_singleton()->get_viewport_control();
} }
if (node) if (node && node->is_connected("settings_changed", this, "_tileset_settings_changed")) {
node->disconnect("settings_changed", this, "_tileset_settings_changed"); node->disconnect("settings_changed", this, "_tileset_settings_changed");
}
if (p_tile_map) { if (p_tile_map) {
node = Object::cast_to<TileMap>(p_tile_map); node = Object::cast_to<TileMap>(p_tile_map);
@ -1843,8 +1845,9 @@ void TileMapEditor::edit(Node *p_tile_map) {
_update_palette(); _update_palette();
} }
if (node) if (node && !node->is_connected("settings_changed", this, "_tileset_settings_changed")) {
node->connect("settings_changed", this, "_tileset_settings_changed"); node->connect("settings_changed", this, "_tileset_settings_changed");
}
_clear_bucket_cache(); _clear_bucket_cache();
} }

View File

@ -980,8 +980,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
// Only flush stdout in debug builds by default, as spamming `print()` will // Only flush stdout in debug builds by default, as spamming `print()` will
// decrease performance if this is enabled. // decrease performance if this is enabled.
GLOBAL_DEF("application/run/flush_stdout_on_print", false); GLOBAL_DEF_RST("application/run/flush_stdout_on_print", false);
GLOBAL_DEF("application/run/flush_stdout_on_print.debug", true); GLOBAL_DEF_RST("application/run/flush_stdout_on_print.debug", true);
GLOBAL_DEF("logging/file_logging/enable_file_logging", false); GLOBAL_DEF("logging/file_logging/enable_file_logging", false);
// Only file logging by default on desktop platforms as logs can't be // Only file logging by default on desktop platforms as logs can't be
@ -1029,6 +1029,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
if (quiet_stdout) if (quiet_stdout)
_print_line_enabled = false; _print_line_enabled = false;
Logger::set_flush_stdout_on_print(ProjectSettings::get_singleton()->get("application/run/flush_stdout_on_print"));
OS::get_singleton()->set_cmdline(execpath, main_args); OS::get_singleton()->set_cmdline(execpath, main_args);
GLOBAL_DEF("rendering/quality/driver/driver_name", "GLES3"); GLOBAL_DEF("rendering/quality/driver/driver_name", "GLES3");

View File

@ -124,6 +124,22 @@
Configure the [CryptoKey] to use when [member use_dtls] is [code]true[/code]. Remember to also call [method set_dtls_certificate] to setup your [X509Certificate]. Configure the [CryptoKey] to use when [member use_dtls] is [code]true[/code]. Remember to also call [method set_dtls_certificate] to setup your [X509Certificate].
</description> </description>
</method> </method>
<method name="set_peer_timeout">
<return type="void">
</return>
<argument index="0" name="id" type="int">
</argument>
<argument index="1" name="timeout_limit" type="int">
</argument>
<argument index="2" name="timeout_min" type="int">
</argument>
<argument index="3" name="timeout_max" type="int">
</argument>
<description>
Sets the timeout parameters for a peer. The timeout parameters control how and when a peer will timeout from a failure to acknowledge reliable traffic. Timeout values are expressed in milliseconds.
The [code]timeout_limit[/code] is a factor that, multiplied by a value based on the avarage round trip time, will determine the timeout limit for a reliable packet. When that limit is reached, the timeout will be doubled, and the peer will be disconnected if that limit has reached [code]timeout_min[/code]. The [code]timeout_max[/code] parameter, on the other hand, defines a fixed timeout for which any packet must be acknowledged or the peer will be dropped.
</description>
</method>
</methods> </methods>
<members> <members>
<member name="always_ordered" type="bool" setter="set_always_ordered" getter="is_always_ordered" default="false"> <member name="always_ordered" type="bool" setter="set_always_ordered" getter="is_always_ordered" default="false">

View File

@ -825,6 +825,14 @@ int NetworkedMultiplayerENet::get_peer_port(int p_peer_id) const {
#endif #endif
} }
void NetworkedMultiplayerENet::set_peer_timeout(int p_peer_id, int p_timeout_limit, int p_timeout_min, int p_timeout_max) {
ERR_FAIL_COND_MSG(!peer_map.has(p_peer_id), vformat("Peer ID %d not found in the list of peers.", p_peer_id));
ERR_FAIL_COND_MSG(!is_server() && p_peer_id != 1, "Can't change the timeout of peers other then the server when acting as a client.");
ERR_FAIL_COND_MSG(peer_map[p_peer_id] == nullptr, vformat("Peer ID %d found in the list of peers, but is null.", p_peer_id));
ERR_FAIL_COND_MSG(p_timeout_limit > p_timeout_min || p_timeout_min > p_timeout_max, "Timeout limit must be less than minimum timeout, which itself must be less then maximum timeout");
enet_peer_timeout(peer_map[p_peer_id], p_timeout_limit, p_timeout_min, p_timeout_max);
}
void NetworkedMultiplayerENet::set_transfer_channel(int p_channel) { void NetworkedMultiplayerENet::set_transfer_channel(int p_channel) {
ERR_FAIL_COND_MSG(p_channel < -1 || p_channel >= channel_count, vformat("The transfer channel must be set between 0 and %d, inclusive (got %d).", channel_count - 1, p_channel)); ERR_FAIL_COND_MSG(p_channel < -1 || p_channel >= channel_count, vformat("The transfer channel must be set between 0 and %d, inclusive (got %d).", channel_count - 1, p_channel));
@ -882,6 +890,7 @@ void NetworkedMultiplayerENet::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_dtls_verify_enabled"), &NetworkedMultiplayerENet::is_dtls_verify_enabled); ClassDB::bind_method(D_METHOD("is_dtls_verify_enabled"), &NetworkedMultiplayerENet::is_dtls_verify_enabled);
ClassDB::bind_method(D_METHOD("get_peer_address", "id"), &NetworkedMultiplayerENet::get_peer_address); ClassDB::bind_method(D_METHOD("get_peer_address", "id"), &NetworkedMultiplayerENet::get_peer_address);
ClassDB::bind_method(D_METHOD("get_peer_port", "id"), &NetworkedMultiplayerENet::get_peer_port); ClassDB::bind_method(D_METHOD("get_peer_port", "id"), &NetworkedMultiplayerENet::get_peer_port);
ClassDB::bind_method(D_METHOD("set_peer_timeout", "id", "timeout_limit", "timeout_min", "timeout_max"), &NetworkedMultiplayerENet::set_peer_timeout);
ClassDB::bind_method(D_METHOD("get_packet_channel"), &NetworkedMultiplayerENet::get_packet_channel); ClassDB::bind_method(D_METHOD("get_packet_channel"), &NetworkedMultiplayerENet::get_packet_channel);
ClassDB::bind_method(D_METHOD("get_last_packet_channel"), &NetworkedMultiplayerENet::get_last_packet_channel); ClassDB::bind_method(D_METHOD("get_last_packet_channel"), &NetworkedMultiplayerENet::get_last_packet_channel);

View File

@ -129,6 +129,7 @@ public:
virtual IP_Address get_peer_address(int p_peer_id) const; virtual IP_Address get_peer_address(int p_peer_id) const;
virtual int get_peer_port(int p_peer_id) const; virtual int get_peer_port(int p_peer_id) const;
void set_peer_timeout(int p_peer_id, int p_timeout_limit, int p_timeout_min, int p_timeout_max);
Error create_server(int p_port, int p_max_clients = 32, int p_in_bandwidth = 0, int p_out_bandwidth = 0); Error create_server(int p_port, int p_max_clients = 32, int p_in_bandwidth = 0, int p_out_bandwidth = 0);
Error create_client(const String &p_address, int p_port, int p_in_bandwidth = 0, int p_out_bandwidth = 0, int p_client_port = 0); Error create_client(const String &p_address, int p_port, int p_in_bandwidth = 0, int p_out_bandwidth = 0, int p_client_port = 0);

View File

@ -0,0 +1,27 @@
namespace Godot
{
public partial class PackedScene
{
/// <summary>
/// Instantiates the scene's node hierarchy, erroring on failure.
/// Triggers child scene instantiation(s). Triggers a
/// `Node.NotificationInstanced` notification on the root node.
/// </summary>
/// <typeparam name="T">The type to cast to. Should be a descendant of Node.</typeparam>
public T Instance<T>(PackedScene.GenEditState editState = (PackedScene.GenEditState)0) where T : class
{
return (T)(object)Instance(editState);
}
/// <summary>
/// Instantiates the scene's node hierarchy, returning null on failure.
/// Triggers child scene instantiation(s). Triggers a
/// `Node.NotificationInstanced` notification on the root node.
/// </summary>
/// <typeparam name="T">The type to cast to. Should be a descendant of Node.</typeparam>
public T InstanceOrNull<T>(PackedScene.GenEditState editState = (PackedScene.GenEditState)0) where T : class
{
return Instance(editState) as T;
}
}
}

View File

@ -28,6 +28,7 @@
<Compile Include="Core\DynamicObject.cs" /> <Compile Include="Core\DynamicObject.cs" />
<Compile Include="Core\Extensions\NodeExtensions.cs" /> <Compile Include="Core\Extensions\NodeExtensions.cs" />
<Compile Include="Core\Extensions\ObjectExtensions.cs" /> <Compile Include="Core\Extensions\ObjectExtensions.cs" />
<Compile Include="Core\Extensions\PackedSceneExtensions.cs" />
<Compile Include="Core\Extensions\ResourceLoaderExtensions.cs" /> <Compile Include="Core\Extensions\ResourceLoaderExtensions.cs" />
<Compile Include="Core\GD.cs" /> <Compile Include="Core\GD.cs" />
<Compile Include="Core\GodotSynchronizationContext.cs" /> <Compile Include="Core\GodotSynchronizationContext.cs" />

View File

@ -399,13 +399,16 @@ void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug) {
static const int subdiv_value[SUBDIV_MAX] = { 7, 8, 9, 10 }; static const int subdiv_value[SUBDIV_MAX] = { 7, 8, 9, 10 };
p_from_node = p_from_node ? p_from_node : get_parent();
ERR_FAIL_NULL(p_from_node);
VoxelLightBaker baker; VoxelLightBaker baker;
baker.begin_bake(subdiv_value[subdiv], AABB(-extents, extents * 2.0)); baker.begin_bake(subdiv_value[subdiv], AABB(-extents, extents * 2.0));
List<PlotMesh> mesh_list; List<PlotMesh> mesh_list;
_find_meshes(p_from_node ? p_from_node : get_parent(), mesh_list); _find_meshes(p_from_node, mesh_list);
if (bake_begin_function) { if (bake_begin_function) {
bake_begin_function(mesh_list.size() + 1); bake_begin_function(mesh_list.size() + 1);

View File

@ -62,8 +62,10 @@ void Joint::_body_exit_tree(const ObjectID &p_body_id) {
void Joint::_update_joint(bool p_only_free) { void Joint::_update_joint(bool p_only_free) {
if (joint.is_valid()) { if (joint.is_valid()) {
if (ba.is_valid() && bb.is_valid()) if (ba.is_valid() && bb.is_valid()) {
PhysicsServer::get_singleton()->body_remove_collision_exception(ba, bb); PhysicsServer::get_singleton()->body_remove_collision_exception(ba, bb);
PhysicsServer::get_singleton()->body_remove_collision_exception(bb, ba);
}
PhysicsServer::get_singleton()->free(joint); PhysicsServer::get_singleton()->free(joint);
joint = RID(); joint = RID();

View File

@ -376,6 +376,7 @@ bool HTTPRequest::_update_connection() {
} else if (client->get_status() == HTTPClient::STATUS_DISCONNECTED) { } else if (client->get_status() == HTTPClient::STATUS_DISCONNECTED) {
// We read till EOF, with no errors. Request is done. // We read till EOF, with no errors. Request is done.
call_deferred("_request_done", RESULT_SUCCESS, response_code, response_headers, body); call_deferred("_request_done", RESULT_SUCCESS, response_code, response_headers, body);
return true;
} }
return false; return false;

View File

@ -546,12 +546,12 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
if (hexa_found || str.length() != 1 || str[0] != '0') if (hexa_found || str.length() != 1 || str[0] != '0')
return _make_token(TK_ERROR, "Invalid numeric constant"); return _make_token(TK_ERROR, "Invalid numeric constant");
hexa_found = true; hexa_found = true;
} else if (GETCHAR(i) == 'e') { } else if (GETCHAR(i) == 'e' && !hexa_found) {
if (hexa_found || exponent_found || float_suffix_found) if (exponent_found || float_suffix_found)
return _make_token(TK_ERROR, "Invalid numeric constant"); return _make_token(TK_ERROR, "Invalid numeric constant");
exponent_found = true; exponent_found = true;
} else if (GETCHAR(i) == 'f') { } else if (GETCHAR(i) == 'f' && !hexa_found) {
if (hexa_found || exponent_found) if (exponent_found)
return _make_token(TK_ERROR, "Invalid numeric constant"); return _make_token(TK_ERROR, "Invalid numeric constant");
float_suffix_found = true; float_suffix_found = true;
} else if (_is_number(GETCHAR(i))) { } else if (_is_number(GETCHAR(i))) {
@ -4698,16 +4698,16 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
pos = _get_tkpos(); pos = _get_tkpos();
tk = _get_token(); tk = _get_token();
if (tk.type != TK_SEMICOLON) { if (tk.type != TK_SEMICOLON) {
//all is good
_set_error("Expected ';' after discard"); _set_error("Expected ';' after discard");
return ERR_PARSE_ERROR;
} }
p_block->statements.push_back(flow); p_block->statements.push_back(flow);
} else if (tk.type == TK_CF_BREAK) { } else if (tk.type == TK_CF_BREAK) {
if (!p_can_break) { if (!p_can_break) {
//all is good _set_error("'break' is not allowed outside of a loop or 'switch' statement");
_set_error("Breaking is not allowed here"); return ERR_PARSE_ERROR;
} }
ControlFlowNode *flow = alloc_node<ControlFlowNode>(); ControlFlowNode *flow = alloc_node<ControlFlowNode>();
@ -4716,8 +4716,8 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
pos = _get_tkpos(); pos = _get_tkpos();
tk = _get_token(); tk = _get_token();
if (tk.type != TK_SEMICOLON) { if (tk.type != TK_SEMICOLON) {
//all is good
_set_error("Expected ';' after break"); _set_error("Expected ';' after break");
return ERR_PARSE_ERROR;
} }
p_block->statements.push_back(flow); p_block->statements.push_back(flow);
@ -4733,8 +4733,8 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
} else if (tk.type == TK_CF_CONTINUE) { } else if (tk.type == TK_CF_CONTINUE) {
if (!p_can_continue) { if (!p_can_continue) {
//all is good _set_error("'continue' is not allowed outside of a loop");
_set_error("Continuing is not allowed here"); return ERR_PARSE_ERROR;
} }
ControlFlowNode *flow = alloc_node<ControlFlowNode>(); ControlFlowNode *flow = alloc_node<ControlFlowNode>();
@ -4745,6 +4745,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
if (tk.type != TK_SEMICOLON) { if (tk.type != TK_SEMICOLON) {
//all is good //all is good
_set_error("Expected ';' after continue"); _set_error("Expected ';' after continue");
return ERR_PARSE_ERROR;
} }
p_block->statements.push_back(flow); p_block->statements.push_back(flow);