Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/editor/project_upgrade/project_converter_3_to_4.cpp
21520 views
1
/**************************************************************************/
2
/* project_converter_3_to_4.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#include "project_converter_3_to_4.h"
32
33
#ifndef DISABLE_DEPRECATED
34
35
#include "core/error/error_macros.h"
36
#include "core/io/dir_access.h"
37
#include "core/io/file_access.h"
38
#include "core/object/ref_counted.h"
39
#include "core/os/keyboard.h"
40
#include "core/os/time.h"
41
#include "core/templates/list.h"
42
#include "editor/project_upgrade/renames_map_3_to_4.h"
43
44
#include "modules/regex/regex.h"
45
46
// Find "OS.set_property(x)", capturing x into $1.
47
static String make_regex_gds_os_property_set(const String &name_set) {
48
return String("\\bOS\\.") + name_set + "\\s*\\((.*)\\)";
49
}
50
// Find "OS.property = x", capturing x into $1 or $2.
51
static String make_regex_gds_os_property_assign(const String &name) {
52
return String("\\bOS\\.") + name + "\\s*=\\s*([^#]+)";
53
}
54
// Find "OS.property" OR "OS.get_property()" / "OS.is_property()".
55
static String make_regex_gds_os_property_get(const String &name, const String &get) {
56
return String("\\bOS\\.(") + get + "_)?" + name + "(\\s*\\(\\s*\\))?";
57
}
58
59
class ProjectConverter3To4::RegExContainer {
60
public:
61
// Custom GDScript.
62
RegEx reg_is_empty = RegEx("\\bempty\\(");
63
RegEx reg_super = RegEx("([\t ])\\.([a-zA-Z_])");
64
RegEx reg_json_to = RegEx("\\bto_json\\b");
65
RegEx reg_json_parse = RegEx("([\t ]{0,})([^\n]+)parse_json\\(([^\n]+)");
66
RegEx reg_json_non_new = RegEx("([\t ]{0,})([^\n]+)JSON\\.parse\\(([^\n]+)");
67
RegEx reg_json_print = RegEx("\\bJSON\\b\\.print\\(");
68
RegEx reg_export_simple = RegEx("export[ ]*\\(([a-zA-Z0-9_]+)\\)[ ]*var[ ]+([a-zA-Z0-9_]+)");
69
RegEx reg_export_typed = RegEx("export[ ]*\\(([a-zA-Z0-9_]+)\\)[ ]*var[ ]+([a-zA-Z0-9_]+)[ ]*:[ ]*[a-zA-Z0-9_]+");
70
RegEx reg_export_inferred_type = RegEx("export[ ]*\\([a-zA-Z0-9_]+\\)[ ]*var[ ]+([a-zA-Z0-9_]+)[ ]*:[ ]*=");
71
RegEx reg_export_advanced = RegEx("export[ ]*\\(([^)^\n]+)\\)[ ]*var[ ]+([a-zA-Z0-9_]+)([^\n]+)");
72
RegEx reg_setget_setget = RegEx("var[ ]+([a-zA-Z0-9_]+)([^\n]+?)[ \t]*setget[ \t]+([a-zA-Z0-9_]+)[ \t]*,[ \t]*([a-zA-Z0-9_]+)");
73
RegEx reg_setget_set = RegEx("var[ ]+([a-zA-Z0-9_]+)([^\n]+?)[ \t]*setget[ \t]+([a-zA-Z0-9_]+)[ \t]*[,]*[^\n]*$");
74
RegEx reg_setget_get = RegEx("var[ ]+([a-zA-Z0-9_]+)([^\n]+?)[ \t]*setget[ \t]+,[ \t]*([a-zA-Z0-9_]+)[ \t]*$");
75
RegEx reg_join = RegEx("([\\(\\)a-zA-Z0-9_]+)\\.join\\(([^\n^\\)]+)\\)");
76
RegEx reg_image_lock = RegEx("([a-zA-Z0-9_\\.]+)\\.lock\\(\\)");
77
RegEx reg_image_unlock = RegEx("([a-zA-Z0-9_\\.]+)\\.unlock\\(\\)");
78
RegEx reg_instantiate = RegEx("\\.instance\\(([^\\)]*)\\)");
79
// Simple OS properties with getters/setters.
80
RegEx reg_os_current_screen = RegEx("\\bOS\\.((set_|get_)?)current_screen\\b");
81
RegEx reg_os_min_window_size = RegEx("\\bOS\\.((set_|get_)?)min_window_size\\b");
82
RegEx reg_os_max_window_size = RegEx("\\bOS\\.((set_|get_)?)max_window_size\\b");
83
RegEx reg_os_window_position = RegEx("\\bOS\\.((set_|get_)?)window_position\\b");
84
RegEx reg_os_window_size = RegEx("\\bOS\\.((set_|get_)?)window_size\\b");
85
RegEx reg_os_getset_screen_orient = RegEx("\\bOS\\.(s|g)et_screen_orientation\\b");
86
// OS property getters/setters for non trivial replacements.
87
RegEx reg_os_set_window_resizable = RegEx(make_regex_gds_os_property_set("set_window_resizable"));
88
RegEx reg_os_assign_window_resizable = RegEx(make_regex_gds_os_property_assign("window_resizable"));
89
RegEx reg_os_is_window_resizable = RegEx(make_regex_gds_os_property_get("window_resizable", "is"));
90
RegEx reg_os_set_fullscreen = RegEx(make_regex_gds_os_property_set("set_window_fullscreen"));
91
RegEx reg_os_assign_fullscreen = RegEx(make_regex_gds_os_property_assign("window_fullscreen"));
92
RegEx reg_os_is_fullscreen = RegEx(make_regex_gds_os_property_get("window_fullscreen", "is"));
93
RegEx reg_os_set_maximized = RegEx(make_regex_gds_os_property_set("set_window_maximized"));
94
RegEx reg_os_assign_maximized = RegEx(make_regex_gds_os_property_assign("window_maximized"));
95
RegEx reg_os_is_maximized = RegEx(make_regex_gds_os_property_get("window_maximized", "is"));
96
RegEx reg_os_set_minimized = RegEx(make_regex_gds_os_property_set("set_window_minimized"));
97
RegEx reg_os_assign_minimized = RegEx(make_regex_gds_os_property_assign("window_minimized"));
98
RegEx reg_os_is_minimized = RegEx(make_regex_gds_os_property_get("window_minimized", "is"));
99
RegEx reg_os_set_vsync = RegEx(make_regex_gds_os_property_set("set_use_vsync"));
100
RegEx reg_os_assign_vsync = RegEx(make_regex_gds_os_property_assign("vsync_enabled"));
101
RegEx reg_os_is_vsync = RegEx(make_regex_gds_os_property_get("vsync_enabled", "is"));
102
// OS properties specific cases & specific replacements.
103
RegEx reg_os_assign_screen_orient = RegEx("^(\\s*)OS\\.screen_orientation\\s*=\\s*([^#]+)"); // $1 - indent, $2 - value
104
RegEx reg_os_set_always_on_top = RegEx(make_regex_gds_os_property_set("set_window_always_on_top"));
105
RegEx reg_os_is_always_on_top = RegEx("\\bOS\\.is_window_always_on_top\\s*\\(.*\\)");
106
RegEx reg_os_set_borderless = RegEx(make_regex_gds_os_property_set("set_borderless_window"));
107
RegEx reg_os_get_borderless = RegEx("\\bOS\\.get_borderless_window\\s*\\(\\s*\\)");
108
RegEx reg_os_screen_orient_enum = RegEx("\\bOS\\.SCREEN_ORIENTATION_(\\w+)\\b"); // $1 - constant suffix
109
110
// GDScript keywords.
111
RegEx keyword_gdscript_tool = RegEx("^tool");
112
RegEx keyword_gdscript_export_single = RegEx("^export");
113
RegEx keyword_gdscript_export_multi = RegEx("([\t]+)export\\b");
114
RegEx keyword_gdscript_onready = RegEx("^onready");
115
RegEx keyword_gdscript_remote = RegEx("^remote func");
116
RegEx keyword_gdscript_remotesync = RegEx("^remotesync func");
117
RegEx keyword_gdscript_sync = RegEx("^sync func");
118
RegEx keyword_gdscript_slave = RegEx("^slave func");
119
RegEx keyword_gdscript_puppet = RegEx("^puppet func");
120
RegEx keyword_gdscript_puppetsync = RegEx("^puppetsync func");
121
RegEx keyword_gdscript_master = RegEx("^master func");
122
RegEx keyword_gdscript_mastersync = RegEx("^mastersync func");
123
124
RegEx gdscript_comment = RegEx("^\\s*#");
125
RegEx csharp_comment = RegEx("^\\s*\\/\\/");
126
127
// CSharp keywords.
128
RegEx keyword_csharp_remote = RegEx("\\[Remote(Attribute)?(\\(\\))?\\]");
129
RegEx keyword_csharp_remotesync = RegEx("\\[(Remote)?Sync(Attribute)?(\\(\\))?\\]");
130
RegEx keyword_csharp_puppet = RegEx("\\[(Puppet|Slave)(Attribute)?(\\(\\))?\\]");
131
RegEx keyword_csharp_puppetsync = RegEx("\\[PuppetSync(Attribute)?(\\(\\))?\\]");
132
RegEx keyword_csharp_master = RegEx("\\[Master(Attribute)?(\\(\\))?\\]");
133
RegEx keyword_csharp_mastersync = RegEx("\\[MasterSync(Attribute)?(\\(\\))?\\]");
134
135
// Colors.
136
LocalVector<RegEx *> color_regexes;
137
LocalVector<String> color_renamed;
138
139
RegEx color_hexadecimal_short_constructor = RegEx("Color\\(\"#?([a-fA-F0-9]{1})([a-fA-F0-9]{3})\\b");
140
RegEx color_hexadecimal_full_constructor = RegEx("Color\\(\"#?([a-fA-F0-9]{2})([a-fA-F0-9]{6})\\b");
141
142
// Classes.
143
LocalVector<RegEx *> class_tscn_regexes;
144
LocalVector<RegEx *> class_gd_regexes;
145
LocalVector<RegEx *> class_shader_regexes;
146
147
// Keycode.
148
RegEx input_map_keycode = RegEx("\\b,\"((physical_)?)scancode\":(\\d+)\\b");
149
150
// Button index and joypad axis.
151
RegEx joypad_button_index = RegEx("\\b,\"button_index\":(\\d+),(\"pressure\":\\d+\\.\\d+,\"pressed\":(false|true))\\b");
152
RegEx joypad_axis = RegEx("\\b,\"axis\":(\\d+)\\b");
153
154
// Index represents Godot 3's value, entry represents Godot 4 value equivalency.
155
// i.e: Button4(L1 - Godot3) -> joypad_button_mappings[4]=9 -> Button9(L1 - Godot4).
156
int joypad_button_mappings[23] = { 0, 1, 2, 3, 9, 10, -1 /*L2*/, -1 /*R2*/, 7, 8, 4, 6, 11, 12, 13, 14, 5, 15, 16, 17, 18, 19, 20 };
157
// Entries for L2 and R2 are -1 since they match to joypad axes and no longer to joypad buttons in Godot 4.
158
159
// Animation suffixes.
160
RegEx animation_suffix = RegEx("([\"'])([a-zA-Z0-9_-]+)(-(?:loop|cycle))([\"'])");
161
162
LocalVector<RegEx *> class_regexes;
163
164
RegEx class_temp_tscn = RegEx("\\bTEMP_RENAMED_CLASS.tscn\\b");
165
RegEx class_temp_gd = RegEx("\\bTEMP_RENAMED_CLASS.gd\\b");
166
RegEx class_temp_shader = RegEx("\\bTEMP_RENAMED_CLASS.shader\\b");
167
168
LocalVector<String> class_temp_tscn_renames;
169
LocalVector<String> class_temp_gd_renames;
170
LocalVector<String> class_temp_shader_renames;
171
172
// Common.
173
LocalVector<RegEx *> enum_regexes;
174
LocalVector<RegEx *> gdscript_function_regexes;
175
LocalVector<RegEx *> project_settings_regexes;
176
LocalVector<RegEx *> project_godot_regexes;
177
LocalVector<RegEx *> input_map_regexes;
178
LocalVector<RegEx *> gdscript_properties_regexes;
179
LocalVector<RegEx *> gdscript_signals_regexes;
180
LocalVector<RegEx *> shaders_regexes;
181
LocalVector<RegEx *> builtin_types_regexes;
182
LocalVector<RegEx *> theme_override_regexes;
183
LocalVector<RegEx *> csharp_function_regexes;
184
LocalVector<RegEx *> csharp_properties_regexes;
185
LocalVector<RegEx *> csharp_signal_regexes;
186
187
RegExContainer() {
188
// Common.
189
{
190
// Enum.
191
for (unsigned int current_index = 0; RenamesMap3To4::enum_renames[current_index][0]; current_index++) {
192
enum_regexes.push_back(memnew(RegEx(String("\\b") + RenamesMap3To4::enum_renames[current_index][0] + "\\b")));
193
}
194
// GDScript functions.
195
for (unsigned int current_index = 0; RenamesMap3To4::gdscript_function_renames[current_index][0]; current_index++) {
196
gdscript_function_regexes.push_back(memnew(RegEx(String("\\b") + RenamesMap3To4::gdscript_function_renames[current_index][0] + "\\b")));
197
}
198
// Project Settings in scripts.
199
for (unsigned int current_index = 0; RenamesMap3To4::project_settings_renames[current_index][0]; current_index++) {
200
project_settings_regexes.push_back(memnew(RegEx(String("\\b") + RenamesMap3To4::project_settings_renames[current_index][0] + "\\b")));
201
}
202
// Project Settings in project.godot.
203
for (unsigned int current_index = 0; RenamesMap3To4::project_godot_renames[current_index][0]; current_index++) {
204
project_godot_regexes.push_back(memnew(RegEx(String("\\b") + RenamesMap3To4::project_godot_renames[current_index][0] + "\\b")));
205
}
206
// Input Map.
207
for (unsigned int current_index = 0; RenamesMap3To4::input_map_renames[current_index][0]; current_index++) {
208
input_map_regexes.push_back(memnew(RegEx(String("\\b") + RenamesMap3To4::input_map_renames[current_index][0] + "\\b")));
209
}
210
// GDScript properties.
211
for (unsigned int current_index = 0; RenamesMap3To4::gdscript_properties_renames[current_index][0]; current_index++) {
212
gdscript_properties_regexes.push_back(memnew(RegEx(String("\\b") + RenamesMap3To4::gdscript_properties_renames[current_index][0] + "\\b")));
213
}
214
// GDScript Signals.
215
for (unsigned int current_index = 0; RenamesMap3To4::gdscript_signals_renames[current_index][0]; current_index++) {
216
gdscript_signals_regexes.push_back(memnew(RegEx(String("\\b") + RenamesMap3To4::gdscript_signals_renames[current_index][0] + "\\b")));
217
}
218
// Shaders.
219
for (unsigned int current_index = 0; RenamesMap3To4::shaders_renames[current_index][0]; current_index++) {
220
shaders_regexes.push_back(memnew(RegEx(String("\\b") + RenamesMap3To4::shaders_renames[current_index][0] + "\\b")));
221
}
222
// Builtin types.
223
for (unsigned int current_index = 0; RenamesMap3To4::builtin_types_renames[current_index][0]; current_index++) {
224
builtin_types_regexes.push_back(memnew(RegEx(String("\\b") + RenamesMap3To4::builtin_types_renames[current_index][0] + "\\b")));
225
}
226
// Theme overrides.
227
for (unsigned int current_index = 0; RenamesMap3To4::theme_override_renames[current_index][0]; current_index++) {
228
theme_override_regexes.push_back(memnew(RegEx(String("\\b") + RenamesMap3To4::theme_override_renames[current_index][0] + "\\b")));
229
}
230
// CSharp function renames.
231
for (unsigned int current_index = 0; RenamesMap3To4::csharp_function_renames[current_index][0]; current_index++) {
232
csharp_function_regexes.push_back(memnew(RegEx(String("\\b") + RenamesMap3To4::csharp_function_renames[current_index][0] + "\\b")));
233
}
234
// CSharp properties renames.
235
for (unsigned int current_index = 0; RenamesMap3To4::csharp_properties_renames[current_index][0]; current_index++) {
236
csharp_properties_regexes.push_back(memnew(RegEx(String("\\b") + RenamesMap3To4::csharp_properties_renames[current_index][0] + "\\b")));
237
}
238
// CSharp signals renames.
239
for (unsigned int current_index = 0; RenamesMap3To4::csharp_signals_renames[current_index][0]; current_index++) {
240
csharp_signal_regexes.push_back(memnew(RegEx(String("\\b") + RenamesMap3To4::csharp_signals_renames[current_index][0] + "\\b")));
241
}
242
}
243
244
// Colors.
245
{
246
for (unsigned int current_index = 0; RenamesMap3To4::color_renames[current_index][0]; current_index++) {
247
color_regexes.push_back(memnew(RegEx(String("\\bColor.") + RenamesMap3To4::color_renames[current_index][0] + "\\b")));
248
color_renamed.push_back(String("Color.") + RenamesMap3To4::color_renames[current_index][1]);
249
}
250
}
251
// Classes.
252
{
253
for (unsigned int current_index = 0; RenamesMap3To4::class_renames[current_index][0]; current_index++) {
254
const String class_name = RenamesMap3To4::class_renames[current_index][0];
255
class_tscn_regexes.push_back(memnew(RegEx(String("\\b") + class_name + ".tscn\\b")));
256
class_gd_regexes.push_back(memnew(RegEx(String("\\b") + class_name + ".gd\\b")));
257
class_shader_regexes.push_back(memnew(RegEx(String("\\b") + class_name + ".shader\\b")));
258
259
class_regexes.push_back(memnew(RegEx(String("\\b") + class_name + "\\b")));
260
261
class_temp_tscn_renames.push_back(class_name + ".tscn");
262
class_temp_gd_renames.push_back(class_name + ".gd");
263
class_temp_shader_renames.push_back(class_name + ".shader");
264
}
265
}
266
}
267
~RegExContainer() {
268
for (RegEx *regex : color_regexes) {
269
memdelete(regex);
270
}
271
for (unsigned int i = 0; i < class_tscn_regexes.size(); i++) {
272
memdelete(class_tscn_regexes[i]);
273
memdelete(class_gd_regexes[i]);
274
memdelete(class_shader_regexes[i]);
275
memdelete(class_regexes[i]);
276
}
277
for (RegEx *regex : enum_regexes) {
278
memdelete(regex);
279
}
280
for (RegEx *regex : gdscript_function_regexes) {
281
memdelete(regex);
282
}
283
for (RegEx *regex : project_settings_regexes) {
284
memdelete(regex);
285
}
286
for (RegEx *regex : project_godot_regexes) {
287
memdelete(regex);
288
}
289
for (RegEx *regex : input_map_regexes) {
290
memdelete(regex);
291
}
292
for (RegEx *regex : gdscript_properties_regexes) {
293
memdelete(regex);
294
}
295
for (RegEx *regex : gdscript_signals_regexes) {
296
memdelete(regex);
297
}
298
for (RegEx *regex : shaders_regexes) {
299
memdelete(regex);
300
}
301
for (RegEx *regex : builtin_types_regexes) {
302
memdelete(regex);
303
}
304
for (RegEx *regex : theme_override_regexes) {
305
memdelete(regex);
306
}
307
for (RegEx *regex : csharp_function_regexes) {
308
memdelete(regex);
309
}
310
for (RegEx *regex : csharp_properties_regexes) {
311
memdelete(regex);
312
}
313
for (RegEx *regex : csharp_signal_regexes) {
314
memdelete(regex);
315
}
316
}
317
};
318
319
ProjectConverter3To4::ProjectConverter3To4(int p_maximum_file_size_kb, int p_maximum_line_length) {
320
maximum_file_size = p_maximum_file_size_kb * 1024;
321
maximum_line_length = p_maximum_line_length;
322
}
323
324
// Function responsible for converting project.
325
bool ProjectConverter3To4::convert() {
326
print_line("Starting conversion.");
327
uint64_t conversion_start_time = Time::get_singleton()->get_ticks_msec();
328
329
RegExContainer reg_container = RegExContainer();
330
331
int cached_maximum_line_length = maximum_line_length;
332
maximum_line_length = 10000; // Use only for tests bigger value, to not break them.
333
334
ERR_FAIL_COND_V_MSG(!test_array_names(), false, "Cannot start converting due to problems with data in arrays.");
335
ERR_FAIL_COND_V_MSG(!test_conversion(reg_container), false, "Aborting conversion due to validation tests failing");
336
337
maximum_line_length = cached_maximum_line_length;
338
339
// Checking if folder contains valid Godot 3 project.
340
// Project should not be converted more than once.
341
{
342
String converter_text = "; Project was converted by built-in tool to Godot 4";
343
344
ERR_FAIL_COND_V_MSG(!FileAccess::exists("project.godot"), false, "Current working directory doesn't contain a \"project.godot\" file for a Godot 3 project.");
345
346
Error err = OK;
347
String project_godot_content = FileAccess::get_file_as_string("project.godot", &err);
348
349
ERR_FAIL_COND_V_MSG(err != OK, false, "Unable to read \"project.godot\".");
350
ERR_FAIL_COND_V_MSG(project_godot_content.contains(converter_text), false, "Project was already converted with this tool.");
351
352
Ref<FileAccess> file = FileAccess::open("project.godot", FileAccess::WRITE);
353
ERR_FAIL_COND_V_MSG(file.is_null(), false, "Unable to open \"project.godot\".");
354
355
file->store_string(converter_text + "\n" + project_godot_content);
356
}
357
358
Vector<String> collected_files = check_for_files();
359
360
uint32_t converted_files = 0;
361
362
// Check file by file.
363
for (int i = 0; i < collected_files.size(); i++) {
364
String file_name = collected_files[i];
365
Vector<SourceLine> source_lines;
366
uint32_t ignored_lines = 0;
367
{
368
Ref<FileAccess> file = FileAccess::open(file_name, FileAccess::READ);
369
ERR_CONTINUE_MSG(file.is_null(), vformat("Unable to read content of \"%s\".", file_name));
370
while (!file->eof_reached()) {
371
String line = file->get_line();
372
373
SourceLine source_line;
374
source_line.line = line;
375
source_line.is_comment = reg_container.gdscript_comment.search_all(line).size() > 0 || reg_container.csharp_comment.search_all(line).size() > 0;
376
source_lines.append(source_line);
377
}
378
}
379
String file_content_before = collect_string_from_vector(source_lines);
380
uint64_t hash_before = file_content_before.hash();
381
uint64_t file_size = file_content_before.size();
382
print_line(vformat("Trying to convert\t%d/%d file - \"%s\" with size - %d KB", i + 1, collected_files.size(), file_name.trim_prefix("res://"), file_size / 1024));
383
384
Vector<String> reason;
385
bool is_ignored = false;
386
uint64_t start_time = Time::get_singleton()->get_ticks_msec();
387
388
if (file_name.ends_with(".shader")) {
389
DirAccess::remove_file_or_error(file_name.trim_prefix("res://"));
390
file_name = file_name.replace(".shader", ".gdshader");
391
}
392
393
if (file_size < uint64_t(maximum_file_size)) {
394
// ".tscn" must work exactly the same as ".gd" files because they may contain built-in Scripts.
395
if (file_name.ends_with(".gd")) {
396
fix_tool_declaration(source_lines, reg_container);
397
398
rename_classes(source_lines, reg_container); // Using only specialized function.
399
400
rename_common(RenamesMap3To4::enum_renames, reg_container.enum_regexes, source_lines);
401
rename_colors(source_lines, reg_container); // Require to additional rename.
402
403
rename_common(RenamesMap3To4::gdscript_function_renames, reg_container.gdscript_function_regexes, source_lines);
404
rename_gdscript_functions(source_lines, reg_container, false); // Require to additional rename.
405
406
rename_common(RenamesMap3To4::project_settings_renames, reg_container.project_settings_regexes, source_lines);
407
rename_gdscript_keywords(source_lines, reg_container, false);
408
rename_common(RenamesMap3To4::gdscript_properties_renames, reg_container.gdscript_properties_regexes, source_lines);
409
rename_common(RenamesMap3To4::gdscript_signals_renames, reg_container.gdscript_signals_regexes, source_lines);
410
rename_common(RenamesMap3To4::shaders_renames, reg_container.shaders_regexes, source_lines);
411
rename_common(RenamesMap3To4::builtin_types_renames, reg_container.builtin_types_regexes, source_lines);
412
rename_common(RenamesMap3To4::theme_override_renames, reg_container.theme_override_regexes, source_lines);
413
rename_animation_suffixes(source_lines, reg_container);
414
415
custom_rename(source_lines, "\\.shader", ".gdshader");
416
417
convert_hexadecimal_colors(source_lines, reg_container);
418
} else if (file_name.ends_with(".tscn")) {
419
fix_pause_mode(source_lines, reg_container);
420
421
rename_classes(source_lines, reg_container); // Using only specialized function.
422
423
rename_common(RenamesMap3To4::enum_renames, reg_container.enum_regexes, source_lines);
424
rename_colors(source_lines, reg_container); // Require to do additional renames.
425
426
rename_common(RenamesMap3To4::gdscript_function_renames, reg_container.gdscript_function_regexes, source_lines);
427
rename_gdscript_functions(source_lines, reg_container, true); // Require to do additional renames.
428
429
rename_common(RenamesMap3To4::project_settings_renames, reg_container.project_settings_regexes, source_lines);
430
rename_gdscript_keywords(source_lines, reg_container, true);
431
rename_common(RenamesMap3To4::gdscript_properties_renames, reg_container.gdscript_properties_regexes, source_lines);
432
rename_common(RenamesMap3To4::gdscript_signals_renames, reg_container.gdscript_signals_regexes, source_lines);
433
rename_common(RenamesMap3To4::shaders_renames, reg_container.shaders_regexes, source_lines);
434
rename_common(RenamesMap3To4::builtin_types_renames, reg_container.builtin_types_regexes, source_lines);
435
rename_common(RenamesMap3To4::theme_override_renames, reg_container.theme_override_regexes, source_lines);
436
rename_animation_suffixes(source_lines, reg_container);
437
438
custom_rename(source_lines, "\\.shader", ".gdshader");
439
440
convert_hexadecimal_colors(source_lines, reg_container);
441
} else if (file_name.ends_with(".cs")) { // TODO, C# should use different methods.
442
rename_classes(source_lines, reg_container); // Using only specialized function.
443
rename_common(RenamesMap3To4::csharp_function_renames, reg_container.csharp_function_regexes, source_lines);
444
rename_common(RenamesMap3To4::builtin_types_renames, reg_container.builtin_types_regexes, source_lines);
445
rename_common(RenamesMap3To4::csharp_properties_renames, reg_container.csharp_properties_regexes, source_lines);
446
rename_common(RenamesMap3To4::csharp_signals_renames, reg_container.csharp_signal_regexes, source_lines);
447
rename_csharp_functions(source_lines, reg_container);
448
rename_csharp_attributes(source_lines, reg_container);
449
custom_rename(source_lines, "public class ", "public partial class ");
450
convert_hexadecimal_colors(source_lines, reg_container);
451
} else if (file_name.ends_with(".gdshader") || file_name.ends_with(".shader")) {
452
rename_common(RenamesMap3To4::shaders_renames, reg_container.shaders_regexes, source_lines);
453
} else if (file_name.ends_with("tres")) {
454
rename_classes(source_lines, reg_container); // Using only specialized function.
455
456
rename_common(RenamesMap3To4::shaders_renames, reg_container.shaders_regexes, source_lines);
457
rename_common(RenamesMap3To4::builtin_types_renames, reg_container.builtin_types_regexes, source_lines);
458
459
custom_rename(source_lines, "\\.shader", ".gdshader");
460
} else if (file_name.ends_with("project.godot")) {
461
rename_common(RenamesMap3To4::project_godot_renames, reg_container.project_godot_regexes, source_lines);
462
rename_common(RenamesMap3To4::builtin_types_renames, reg_container.builtin_types_regexes, source_lines);
463
rename_input_map_scancode(source_lines, reg_container);
464
rename_joypad_buttons_and_axes(source_lines, reg_container);
465
rename_common(RenamesMap3To4::input_map_renames, reg_container.input_map_regexes, source_lines);
466
custom_rename(source_lines, "config_version=4", "config_version=5");
467
} else if (file_name.ends_with(".csproj")) {
468
// TODO
469
} else if (file_name.ends_with(".import")) {
470
for (SourceLine &source_line : source_lines) {
471
String &line = source_line.line;
472
if (line.contains("nodes/root_type=\"Spatial\"")) {
473
line = "nodes/root_type=\"Node3D\"";
474
} else if (line == "importer=\"ogg_vorbis\"") {
475
line = "importer=\"oggvorbisstr\"";
476
}
477
}
478
} else {
479
ERR_PRINT(file_name + " is not supported!");
480
continue;
481
}
482
483
for (SourceLine &source_line : source_lines) {
484
if (source_line.is_comment) {
485
continue;
486
}
487
488
String &line = source_line.line;
489
if (uint64_t(line.length()) > maximum_line_length) {
490
ignored_lines += 1;
491
}
492
}
493
} else {
494
reason.append(vformat(" ERROR: File has exceeded the maximum size allowed - %d KB", maximum_file_size / 1024));
495
is_ignored = true;
496
}
497
498
uint64_t end_time = Time::get_singleton()->get_ticks_msec();
499
if (is_ignored) {
500
String end_message = vformat(" Checking file took %d ms.", end_time - start_time);
501
print_line(end_message);
502
} else {
503
String file_content_after = collect_string_from_vector(source_lines);
504
uint64_t hash_after = file_content_after.hash64();
505
// Don't need to save file without any changes.
506
// Save if this is a shader, because it was renamed.
507
if (hash_before != hash_after || file_name.ends_with(".gdshader")) {
508
converted_files++;
509
510
Ref<FileAccess> file = FileAccess::open(file_name, FileAccess::WRITE);
511
ERR_CONTINUE_MSG(file.is_null(), vformat("Unable to apply changes to \"%s\", no writing access.", file_name));
512
file->store_string(file_content_after);
513
reason.append(vformat(" File was changed, conversion took %d ms.", end_time - start_time));
514
} else {
515
reason.append(vformat(" File was left unchanged, checking took %d ms.", end_time - start_time));
516
}
517
if (ignored_lines != 0) {
518
reason.append(vformat(" Ignored %d lines, because their length exceeds maximum allowed characters - %d.", ignored_lines, maximum_line_length));
519
}
520
}
521
for (int k = 0; k < reason.size(); k++) {
522
print_line(reason[k]);
523
}
524
}
525
print_line(vformat("Conversion ended - all files(%d), converted files: (%d), not converted files: (%d).", collected_files.size(), converted_files, collected_files.size() - converted_files));
526
uint64_t conversion_end_time = Time::get_singleton()->get_ticks_msec();
527
print_line(vformat("Conversion of all files took %10.3f seconds.", (conversion_end_time - conversion_start_time) / 1000.0));
528
return true;
529
}
530
531
// Function responsible for validating project conversion.
532
bool ProjectConverter3To4::validate_conversion() {
533
print_line("Starting checking if project conversion can be done.");
534
uint64_t conversion_start_time = Time::get_singleton()->get_ticks_msec();
535
536
RegExContainer reg_container = RegExContainer();
537
538
int cached_maximum_line_length = maximum_line_length;
539
maximum_line_length = 10000; // To avoid breaking the tests, only use this for the their larger value.
540
541
ERR_FAIL_COND_V_MSG(!test_array_names(), false, "Cannot start converting due to problems with data in arrays.");
542
ERR_FAIL_COND_V_MSG(!test_conversion(reg_container), false, "Aborting conversion due to validation tests failing");
543
544
maximum_line_length = cached_maximum_line_length;
545
546
// Checking if folder contains valid Godot 3 project.
547
// Project should not be converted more than once.
548
{
549
String conventer_text = "; Project was converted by built-in tool to Godot 4";
550
551
ERR_FAIL_COND_V_MSG(!FileAccess::exists("project.godot"), false, "Current directory doesn't contain any Godot 3 project");
552
553
Error err = OK;
554
String project_godot_content = FileAccess::get_file_as_string("project.godot", &err);
555
556
ERR_FAIL_COND_V_MSG(err != OK, false, "Failed to read content of \"project.godot\" file.");
557
ERR_FAIL_COND_V_MSG(project_godot_content.contains(conventer_text), false, "Project already was converted with this tool.");
558
}
559
560
Vector<String> collected_files = check_for_files();
561
562
uint32_t converted_files = 0;
563
564
// Check file by file.
565
for (int i = 0; i < collected_files.size(); i++) {
566
const String &file_name = collected_files[i];
567
Vector<String> lines;
568
uint32_t ignored_lines = 0;
569
uint64_t file_size = 0;
570
{
571
Ref<FileAccess> file = FileAccess::open(file_name, FileAccess::READ);
572
ERR_CONTINUE_MSG(file.is_null(), vformat("Unable to read content of \"%s\".", file_name));
573
while (!file->eof_reached()) {
574
String line = file->get_line();
575
file_size += line.size();
576
lines.append(line);
577
}
578
}
579
print_line(vformat("Checking for conversion - %d/%d file - \"%s\" with size - %d KB", i + 1, collected_files.size(), file_name.trim_prefix("res://"), file_size / 1024));
580
581
Vector<String> changed_elements;
582
Vector<String> reason;
583
bool is_ignored = false;
584
uint64_t start_time = Time::get_singleton()->get_ticks_msec();
585
586
if (file_name.ends_with(".shader")) {
587
reason.append("\tFile extension will be renamed from \"shader\" to \"gdshader\".");
588
}
589
590
if (file_size < uint64_t(maximum_file_size)) {
591
if (file_name.ends_with(".gd")) {
592
changed_elements.append_array(check_for_rename_classes(lines, reg_container));
593
594
changed_elements.append_array(check_for_rename_common(RenamesMap3To4::enum_renames, reg_container.enum_regexes, lines));
595
changed_elements.append_array(check_for_rename_colors(lines, reg_container));
596
597
changed_elements.append_array(check_for_rename_common(RenamesMap3To4::gdscript_function_renames, reg_container.gdscript_function_regexes, lines));
598
changed_elements.append_array(check_for_rename_gdscript_functions(lines, reg_container, false));
599
600
changed_elements.append_array(check_for_rename_common(RenamesMap3To4::project_settings_renames, reg_container.project_settings_regexes, lines));
601
changed_elements.append_array(check_for_rename_gdscript_keywords(lines, reg_container, false));
602
changed_elements.append_array(check_for_rename_common(RenamesMap3To4::gdscript_properties_renames, reg_container.gdscript_properties_regexes, lines));
603
changed_elements.append_array(check_for_rename_common(RenamesMap3To4::gdscript_signals_renames, reg_container.gdscript_signals_regexes, lines));
604
changed_elements.append_array(check_for_rename_common(RenamesMap3To4::shaders_renames, reg_container.shaders_regexes, lines));
605
changed_elements.append_array(check_for_rename_common(RenamesMap3To4::builtin_types_renames, reg_container.builtin_types_regexes, lines));
606
changed_elements.append_array(check_for_rename_common(RenamesMap3To4::theme_override_renames, reg_container.theme_override_regexes, lines));
607
changed_elements.append_array(check_for_rename_animation_suffixes(lines, reg_container));
608
609
changed_elements.append_array(check_for_custom_rename(lines, "\\.shader", ".gdshader"));
610
} else if (file_name.ends_with(".tscn")) {
611
changed_elements.append_array(check_for_rename_classes(lines, reg_container));
612
613
changed_elements.append_array(check_for_rename_common(RenamesMap3To4::enum_renames, reg_container.enum_regexes, lines));
614
changed_elements.append_array(check_for_rename_colors(lines, reg_container));
615
616
changed_elements.append_array(check_for_rename_common(RenamesMap3To4::gdscript_function_renames, reg_container.gdscript_function_regexes, lines));
617
changed_elements.append_array(check_for_rename_gdscript_functions(lines, reg_container, true));
618
619
changed_elements.append_array(check_for_rename_common(RenamesMap3To4::project_settings_renames, reg_container.project_settings_regexes, lines));
620
changed_elements.append_array(check_for_rename_gdscript_keywords(lines, reg_container, true));
621
changed_elements.append_array(check_for_rename_common(RenamesMap3To4::gdscript_properties_renames, reg_container.gdscript_properties_regexes, lines));
622
changed_elements.append_array(check_for_rename_common(RenamesMap3To4::gdscript_signals_renames, reg_container.gdscript_signals_regexes, lines));
623
changed_elements.append_array(check_for_rename_common(RenamesMap3To4::shaders_renames, reg_container.shaders_regexes, lines));
624
changed_elements.append_array(check_for_rename_common(RenamesMap3To4::builtin_types_renames, reg_container.builtin_types_regexes, lines));
625
changed_elements.append_array(check_for_rename_common(RenamesMap3To4::theme_override_renames, reg_container.theme_override_regexes, lines));
626
changed_elements.append_array(check_for_rename_animation_suffixes(lines, reg_container));
627
628
changed_elements.append_array(check_for_custom_rename(lines, "\\.shader", ".gdshader"));
629
} else if (file_name.ends_with(".cs")) {
630
changed_elements.append_array(check_for_rename_classes(lines, reg_container));
631
changed_elements.append_array(check_for_rename_common(RenamesMap3To4::csharp_function_renames, reg_container.csharp_function_regexes, lines));
632
changed_elements.append_array(check_for_rename_common(RenamesMap3To4::builtin_types_renames, reg_container.builtin_types_regexes, lines));
633
changed_elements.append_array(check_for_rename_common(RenamesMap3To4::csharp_properties_renames, reg_container.csharp_properties_regexes, lines));
634
changed_elements.append_array(check_for_rename_common(RenamesMap3To4::csharp_signals_renames, reg_container.csharp_signal_regexes, lines));
635
changed_elements.append_array(check_for_rename_csharp_functions(lines, reg_container));
636
changed_elements.append_array(check_for_rename_csharp_attributes(lines, reg_container));
637
changed_elements.append_array(check_for_custom_rename(lines, "public class ", "public partial class "));
638
} else if (file_name.ends_with(".gdshader") || file_name.ends_with(".shader")) {
639
changed_elements.append_array(check_for_rename_common(RenamesMap3To4::shaders_renames, reg_container.shaders_regexes, lines));
640
} else if (file_name.ends_with("tres")) {
641
changed_elements.append_array(check_for_rename_classes(lines, reg_container));
642
643
changed_elements.append_array(check_for_rename_common(RenamesMap3To4::shaders_renames, reg_container.shaders_regexes, lines));
644
changed_elements.append_array(check_for_rename_common(RenamesMap3To4::builtin_types_renames, reg_container.builtin_types_regexes, lines));
645
646
changed_elements.append_array(check_for_custom_rename(lines, "\\.shader", ".gdshader"));
647
} else if (file_name.ends_with("project.godot")) {
648
changed_elements.append_array(check_for_rename_common(RenamesMap3To4::project_godot_renames, reg_container.project_godot_regexes, lines));
649
changed_elements.append_array(check_for_rename_common(RenamesMap3To4::builtin_types_renames, reg_container.builtin_types_regexes, lines));
650
changed_elements.append_array(check_for_rename_input_map_scancode(lines, reg_container));
651
changed_elements.append_array(check_for_rename_joypad_buttons_and_axes(lines, reg_container));
652
changed_elements.append_array(check_for_rename_common(RenamesMap3To4::input_map_renames, reg_container.input_map_regexes, lines));
653
} else if (file_name.ends_with(".csproj")) {
654
// TODO
655
} else {
656
ERR_PRINT(vformat("\"%s\", is not supported!", file_name));
657
continue;
658
}
659
660
for (String &line : lines) {
661
if (uint64_t(line.length()) > maximum_line_length) {
662
ignored_lines += 1;
663
}
664
}
665
} else {
666
reason.append(vformat("\tERROR: File has exceeded the maximum size allowed - %d KB.", maximum_file_size / 1024));
667
is_ignored = true;
668
}
669
670
uint64_t end_time = Time::get_singleton()->get_ticks_msec();
671
String end_message = vformat(" Checking file took %10.3f ms.", (end_time - start_time) / 1000.0);
672
if (ignored_lines != 0) {
673
end_message += vformat(" Ignored %d lines, because their length exceeds maximum allowed characters - %d.", ignored_lines, maximum_line_length);
674
}
675
print_line(end_message);
676
677
for (int k = 0; k < reason.size(); k++) {
678
print_line(reason[k]);
679
}
680
681
if (changed_elements.size() > 0 && !is_ignored) {
682
converted_files++;
683
684
for (int k = 0; k < changed_elements.size(); k++) {
685
print_line(String("\t\t") + changed_elements[k]);
686
}
687
}
688
}
689
690
print_line(vformat("Checking for valid conversion ended - all files(%d), files which would be converted(%d), files which would not be converted(%d).", collected_files.size(), converted_files, collected_files.size() - converted_files));
691
uint64_t conversion_end_time = Time::get_singleton()->get_ticks_msec();
692
print_line(vformat("Conversion of all files took %10.3f seconds.", (conversion_end_time - conversion_start_time) / 1000.0));
693
return true;
694
}
695
696
// Collect files which will be checked, excluding ".txt", ".mp4", ".wav" etc. files.
697
Vector<String> ProjectConverter3To4::check_for_files() {
698
Vector<String> collected_files = Vector<String>();
699
700
Vector<String> directories_to_check = Vector<String>();
701
directories_to_check.push_back("res://");
702
703
while (!directories_to_check.is_empty()) {
704
String path = directories_to_check.get(directories_to_check.size() - 1); // Is there any pop_back function?
705
directories_to_check.resize(directories_to_check.size() - 1); // Remove last element
706
707
Ref<DirAccess> dir = DirAccess::open(path);
708
if (dir.is_valid()) {
709
dir->set_include_hidden(true);
710
dir->list_dir_begin();
711
String current_dir = dir->get_current_dir();
712
String file_name = dir->_get_next();
713
714
while (file_name != "") {
715
if (file_name == ".git" || file_name == ".godot") {
716
file_name = dir->_get_next();
717
continue;
718
}
719
if (dir->current_is_dir()) {
720
directories_to_check.append(current_dir.path_join(file_name) + "/");
721
} else {
722
bool proper_extension = false;
723
if (file_name.ends_with(".gd") || file_name.ends_with(".shader") || file_name.ends_with(".gdshader") || file_name.ends_with(".tscn") || file_name.ends_with(".tres") || file_name.ends_with(".godot") || file_name.ends_with(".cs") || file_name.ends_with(".csproj") || file_name.ends_with(".import")) {
724
proper_extension = true;
725
}
726
727
if (proper_extension) {
728
collected_files.append(current_dir.path_join(file_name));
729
}
730
}
731
file_name = dir->_get_next();
732
}
733
} else {
734
print_verbose("Failed to open " + path);
735
}
736
}
737
return collected_files;
738
}
739
740
Vector<SourceLine> ProjectConverter3To4::split_lines(const String &text) {
741
Vector<String> lines = text.split("\n");
742
Vector<SourceLine> source_lines;
743
for (String &line : lines) {
744
SourceLine source_line;
745
source_line.line = line;
746
source_line.is_comment = false;
747
748
source_lines.append(source_line);
749
}
750
return source_lines;
751
}
752
753
// Test expected results of gdscript
754
bool ProjectConverter3To4::test_conversion_gdscript_builtin(const String &name, const String &expected, void (ProjectConverter3To4::*func)(Vector<SourceLine> &, const RegExContainer &, bool), const String &what, const RegExContainer &reg_container, bool builtin_script) {
755
Vector<SourceLine> got = split_lines(name);
756
757
(this->*func)(got, reg_container, builtin_script);
758
String got_str = collect_string_from_vector(got);
759
ERR_FAIL_COND_V_MSG(expected != got_str, false, vformat("Failed to convert %s \"%s\" to \"%s\", got instead \"%s\"", what, name, expected, got_str));
760
761
return true;
762
}
763
764
bool ProjectConverter3To4::test_conversion_with_regex(const String &name, const String &expected, void (ProjectConverter3To4::*func)(Vector<SourceLine> &, const RegExContainer &), const String &what, const RegExContainer &reg_container) {
765
Vector<SourceLine> got = split_lines(name);
766
767
(this->*func)(got, reg_container);
768
String got_str = collect_string_from_vector(got);
769
ERR_FAIL_COND_V_MSG(expected != got_str, false, vformat("Failed to convert %s \"%s\" to \"%s\", got instead \"%s\"", what, name, expected, got_str));
770
771
return true;
772
}
773
774
bool ProjectConverter3To4::test_conversion_basic(const String &name, const String &expected, const char *array[][2], LocalVector<RegEx *> &regex_cache, const String &what) {
775
Vector<SourceLine> got = split_lines(name);
776
777
rename_common(array, regex_cache, got);
778
String got_str = collect_string_from_vector(got);
779
ERR_FAIL_COND_V_MSG(expected != got_str, false, vformat("Failed to convert %s \"%s\" to \"%s\", got instead \"%s\"", what, name, expected, got_str));
780
781
return true;
782
}
783
784
// Validate if conversions are proper.
785
bool ProjectConverter3To4::test_conversion(RegExContainer &reg_container) {
786
bool valid = true;
787
788
valid = valid && test_conversion_with_regex("tool", "@tool", &ProjectConverter3To4::fix_tool_declaration, "gdscript keyword", reg_container);
789
valid = valid && test_conversion_with_regex("\n tool", "\n tool", &ProjectConverter3To4::fix_tool_declaration, "gdscript keyword", reg_container);
790
valid = valid && test_conversion_with_regex("\n\ntool", "@tool\n\n", &ProjectConverter3To4::fix_tool_declaration, "gdscript keyword", reg_container);
791
792
valid = valid && test_conversion_with_regex("pause_mode = 2", "pause_mode = 3", &ProjectConverter3To4::fix_pause_mode, "pause_mode", reg_container);
793
valid = valid && test_conversion_with_regex("pause_mode = 1", "pause_mode = 1", &ProjectConverter3To4::fix_pause_mode, "pause_mode", reg_container);
794
valid = valid && test_conversion_with_regex("pause_mode = 3", "pause_mode = 3", &ProjectConverter3To4::fix_pause_mode, "pause_mode", reg_container);
795
valid = valid && test_conversion_with_regex("somepause_mode = 2", "somepause_mode = 2", &ProjectConverter3To4::fix_pause_mode, "pause_mode", reg_container);
796
valid = valid && test_conversion_with_regex("pause_mode_ext = 2", "pause_mode_ext = 2", &ProjectConverter3To4::fix_pause_mode, "pause_mode", reg_container);
797
798
valid = valid && test_conversion_basic("TYPE_REAL", "TYPE_FLOAT", RenamesMap3To4::enum_renames, reg_container.enum_regexes, "enum");
799
800
valid = valid && test_conversion_basic("can_instance", "can_instantiate", RenamesMap3To4::gdscript_function_renames, reg_container.gdscript_function_regexes, "gdscript function");
801
802
valid = valid && test_conversion_basic("CanInstance", "CanInstantiate", RenamesMap3To4::csharp_function_renames, reg_container.csharp_function_regexes, "csharp function");
803
804
valid = valid && test_conversion_basic("translation", "position", RenamesMap3To4::gdscript_properties_renames, reg_container.gdscript_properties_regexes, "gdscript property");
805
806
valid = valid && test_conversion_basic("Translation", "Position", RenamesMap3To4::csharp_properties_renames, reg_container.csharp_properties_regexes, "csharp property");
807
808
valid = valid && test_conversion_basic("NORMALMAP", "NORMAL_MAP", RenamesMap3To4::shaders_renames, reg_container.shaders_regexes, "shader");
809
810
valid = valid && test_conversion_basic("text_entered", "text_submitted", RenamesMap3To4::gdscript_signals_renames, reg_container.gdscript_signals_regexes, "gdscript signal");
811
812
valid = valid && test_conversion_basic("TextEntered", "TextSubmitted", RenamesMap3To4::csharp_signals_renames, reg_container.csharp_signal_regexes, "csharp signal");
813
814
valid = valid && test_conversion_basic("audio/channel_disable_threshold_db", "audio/buses/channel_disable_threshold_db", RenamesMap3To4::project_settings_renames, reg_container.project_settings_regexes, "project setting");
815
816
valid = valid && test_conversion_basic("\"device\":-1,\"alt\":false,\"shift\":false,\"control\":false,\"meta\":false,\"doubleclick\":false,\"scancode\":0,\"physical_scancode\":16777254,\"script\":null", "\"device\":-1,\"alt_pressed\":false,\"shift_pressed\":false,\"ctrl_pressed\":false,\"meta_pressed\":false,\"double_click\":false,\"keycode\":0,\"physical_keycode\":16777254,\"script\":null", RenamesMap3To4::input_map_renames, reg_container.input_map_regexes, "input map");
817
818
valid = valid && test_conversion_basic("Transform", "Transform3D", RenamesMap3To4::builtin_types_renames, reg_container.builtin_types_regexes, "builtin type");
819
820
valid = valid && test_conversion_basic("custom_constants/margin_right", "theme_override_constants/margin_right", RenamesMap3To4::theme_override_renames, reg_container.theme_override_regexes, "theme overrides");
821
822
// Custom Renames.
823
824
valid = valid && test_conversion_with_regex("(Connect(A,B,C,D,E,F,G) != OK):", "(Connect(A, new Callable(B, C), D, E, F, G) != OK):", &ProjectConverter3To4::rename_csharp_functions, "custom rename csharp", reg_container);
825
valid = valid && test_conversion_with_regex("(Disconnect(A,B,C) != OK):", "(Disconnect(A, new Callable(B, C)) != OK):", &ProjectConverter3To4::rename_csharp_functions, "custom rename csharp", reg_container);
826
valid = valid && test_conversion_with_regex("(IsConnected(A,B,C) != OK):", "(IsConnected(A, new Callable(B, C)) != OK):", &ProjectConverter3To4::rename_csharp_functions, "custom rename", reg_container);
827
828
valid = valid && test_conversion_with_regex("[Remote]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container);
829
valid = valid && test_conversion_with_regex("[RemoteSync]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container);
830
valid = valid && test_conversion_with_regex("[Sync]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container);
831
valid = valid && test_conversion_with_regex("[Slave]", "[RPC]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container);
832
valid = valid && test_conversion_with_regex("[Puppet]", "[RPC]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container);
833
valid = valid && test_conversion_with_regex("[PuppetSync]", "[RPC(CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container);
834
valid = valid && test_conversion_with_regex("[Master]", "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using Multiplayer.GetRemoteSenderId()\n[RPC]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container);
835
valid = valid && test_conversion_with_regex("[MasterSync]", "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using Multiplayer.GetRemoteSenderId()\n[RPC(CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container);
836
837
valid = valid && test_conversion_gdscript_builtin("\tif OS.window_resizable: pass", "\tif (not get_window().unresizable): pass", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
838
valid = valid && test_conversion_gdscript_builtin("\tif OS.is_window_resizable(): pass", "\tif (not get_window().unresizable): pass", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
839
valid = valid && test_conversion_gdscript_builtin("\tOS.set_window_resizable(Settings.resizable)", "\tget_window().unresizable = not (Settings.resizable)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
840
valid = valid && test_conversion_gdscript_builtin("\tOS.window_resizable = Settings.resizable", "\tget_window().unresizable = not (Settings.resizable)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
841
842
valid = valid && test_conversion_gdscript_builtin("\tif OS.window_fullscreen: pass", "\tif ((get_window().mode == Window.MODE_EXCLUSIVE_FULLSCREEN) or (get_window().mode == Window.MODE_FULLSCREEN)): pass", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
843
valid = valid && test_conversion_gdscript_builtin("\tif OS.is_window_fullscreen(): pass", "\tif ((get_window().mode == Window.MODE_EXCLUSIVE_FULLSCREEN) or (get_window().mode == Window.MODE_FULLSCREEN)): pass", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
844
valid = valid && test_conversion_gdscript_builtin("\tOS.set_window_fullscreen(Settings.fullscreen)", "\tget_window().mode = Window.MODE_EXCLUSIVE_FULLSCREEN if (Settings.fullscreen) else Window.MODE_WINDOWED", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
845
valid = valid && test_conversion_gdscript_builtin("\tOS.window_fullscreen = Settings.fullscreen", "\tget_window().mode = Window.MODE_EXCLUSIVE_FULLSCREEN if (Settings.fullscreen) else Window.MODE_WINDOWED", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
846
847
valid = valid && test_conversion_gdscript_builtin("\tif OS.window_maximized: pass", "\tif (get_window().mode == Window.MODE_MAXIMIZED): pass", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
848
valid = valid && test_conversion_gdscript_builtin("\tif OS.is_window_maximized(): pass", "\tif (get_window().mode == Window.MODE_MAXIMIZED): pass", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
849
valid = valid && test_conversion_gdscript_builtin("\tOS.set_window_maximized(Settings.maximized)", "\tget_window().mode = Window.MODE_MAXIMIZED if (Settings.maximized) else Window.MODE_WINDOWED", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
850
valid = valid && test_conversion_gdscript_builtin("\tOS.window_maximized = Settings.maximized", "\tget_window().mode = Window.MODE_MAXIMIZED if (Settings.maximized) else Window.MODE_WINDOWED", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
851
852
valid = valid && test_conversion_gdscript_builtin("\tif OS.window_minimized: pass", "\tif (get_window().mode == Window.MODE_MINIMIZED): pass", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
853
valid = valid && test_conversion_gdscript_builtin("\tif OS.is_window_minimized(): pass", "\tif (get_window().mode == Window.MODE_MINIMIZED): pass", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
854
valid = valid && test_conversion_gdscript_builtin("\tOS.set_window_minimized(Settings.minimized)", "\tget_window().mode = Window.MODE_MINIMIZED if (Settings.minimized) else Window.MODE_WINDOWED", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
855
valid = valid && test_conversion_gdscript_builtin("\tOS.window_minimized = Settings.minimized", "\tget_window().mode = Window.MODE_MINIMIZED if (Settings.minimized) else Window.MODE_WINDOWED", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
856
857
valid = valid && test_conversion_gdscript_builtin("\tif OS.vsync_enabled: pass", "\tif (DisplayServer.window_get_vsync_mode() != DisplayServer.VSYNC_DISABLED): pass", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
858
valid = valid && test_conversion_gdscript_builtin("\tif OS.is_vsync_enabled(): pass", "\tif (DisplayServer.window_get_vsync_mode() != DisplayServer.VSYNC_DISABLED): pass", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
859
valid = valid && test_conversion_gdscript_builtin("\tOS.set_use_vsync(Settings.vsync)", "\tDisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_ENABLED if (Settings.vsync) else DisplayServer.VSYNC_DISABLED)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
860
valid = valid && test_conversion_gdscript_builtin("\tOS.vsync_enabled = Settings.vsync", "\tDisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_ENABLED if (Settings.vsync) else DisplayServer.VSYNC_DISABLED)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
861
862
valid = valid && test_conversion_gdscript_builtin("\tif OS.screen_orientation = OS.SCREEN_ORIENTATION_VERTICAL: pass", "\tif DisplayServer.screen_get_orientation() = DisplayServer.SCREEN_VERTICAL: pass", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
863
valid = valid && test_conversion_gdscript_builtin("\tif OS.get_screen_orientation() = OS.SCREEN_ORIENTATION_LANDSCAPE: pass", "\tif DisplayServer.screen_get_orientation() = DisplayServer.SCREEN_LANDSCAPE: pass", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
864
valid = valid && test_conversion_gdscript_builtin("\tOS.set_screen_orientation(Settings.orient)", "\tDisplayServer.screen_set_orientation(Settings.orient)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
865
valid = valid && test_conversion_gdscript_builtin("\tOS.screen_orientation = Settings.orient", "\tDisplayServer.screen_set_orientation(Settings.orient)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
866
867
valid = valid && test_conversion_gdscript_builtin("\tif OS.is_window_always_on_top(): pass", "\tif get_window().always_on_top: pass", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
868
valid = valid && test_conversion_gdscript_builtin("\tOS.set_window_always_on_top(Settings.alwaystop)", "\tget_window().always_on_top = (Settings.alwaystop)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
869
870
valid = valid && test_conversion_gdscript_builtin("\tif OS.get_borderless_window(): pass", "\tif get_window().borderless: pass", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
871
valid = valid && test_conversion_gdscript_builtin("\tOS.set_borderless_window(Settings.borderless)", "\tget_window().borderless = (Settings.borderless)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
872
873
valid = valid && test_conversion_gdscript_builtin("\tvar aa = roman(r.move_and_slide( a, b, c, d, e, f )) # Roman", "\tr.set_velocity(a)\n\tr.set_up_direction(b)\n\tr.set_floor_stop_on_slope_enabled(c)\n\tr.set_max_slides(d)\n\tr.set_floor_max_angle(e)\n\t# TODOConverter3To4 infinite_inertia were removed in Godot 4 - previous value `f`\n\tr.move_and_slide()\n\tvar aa = roman(r.velocity) # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
874
valid = valid && test_conversion_gdscript_builtin("\tmove_and_slide( a, b, c, d, e, f ) # Roman", "\tset_velocity(a)\n\tset_up_direction(b)\n\tset_floor_stop_on_slope_enabled(c)\n\tset_max_slides(d)\n\tset_floor_max_angle(e)\n\t# TODOConverter3To4 infinite_inertia were removed in Godot 4 - previous value `f`\n\tmove_and_slide() # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
875
valid = valid && test_conversion_gdscript_builtin("\tvar aa = roman(r.move_and_slide_with_snap( a, g, b, c, d, e, f )) # Roman", "\tr.set_velocity(a)\n\t# TODOConverter3To4 looks that snap in Godot 4 is float, not vector like in Godot 3 - previous value `g`\n\tr.set_up_direction(b)\n\tr.set_floor_stop_on_slope_enabled(c)\n\tr.set_max_slides(d)\n\tr.set_floor_max_angle(e)\n\t# TODOConverter3To4 infinite_inertia were removed in Godot 4 - previous value `f`\n\tr.move_and_slide()\n\tvar aa = roman(r.velocity) # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
876
valid = valid && test_conversion_gdscript_builtin("\tmove_and_slide_with_snap( a, g, b, c, d, e, f ) # Roman", "\tset_velocity(a)\n\t# TODOConverter3To4 looks that snap in Godot 4 is float, not vector like in Godot 3 - previous value `g`\n\tset_up_direction(b)\n\tset_floor_stop_on_slope_enabled(c)\n\tset_max_slides(d)\n\tset_floor_max_angle(e)\n\t# TODOConverter3To4 infinite_inertia were removed in Godot 4 - previous value `f`\n\tmove_and_slide() # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
877
878
valid = valid && test_conversion_gdscript_builtin("remove_and_slide(a,b,c,d,e,f)", "remove_and_slide(a,b,c,d,e,f)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
879
880
valid = valid && test_conversion_gdscript_builtin("list_dir_begin( a , b )", "list_dir_begin() # TODOConverter3To4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
881
valid = valid && test_conversion_gdscript_builtin("list_dir_begin( a )", "list_dir_begin() # TODOConverter3To4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
882
valid = valid && test_conversion_gdscript_builtin("list_dir_begin( )", "list_dir_begin() # TODOConverter3To4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
883
884
valid = valid && test_conversion_gdscript_builtin("sort_custom( a , b )", "sort_custom(Callable(a, b))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
885
886
valid = valid && test_conversion_gdscript_builtin("func c(var a, var b)", "func c(a, b)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
887
888
valid = valid && test_conversion_gdscript_builtin("draw_line(1, 2, 3, 4, 5)", "draw_line(1, 2, 3, 4)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
889
890
valid = valid && test_conversion_gdscript_builtin("\timage.lock()", "\tfalse # image.lock() # TODOConverter3To4, Image no longer requires locking, `false` helps to not break one line if/else, so it can freely be removed", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
891
valid = valid && test_conversion_gdscript_builtin("\timage.unlock()", "\tfalse # image.unlock() # TODOConverter3To4, Image no longer requires locking, `false` helps to not break one line if/else, so it can freely be removed", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
892
valid = valid && test_conversion_gdscript_builtin("\troman.image.unlock()", "\tfalse # roman.image.unlock() # TODOConverter3To4, Image no longer requires locking, `false` helps to not break one line if/else, so it can freely be removed", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
893
valid = valid && test_conversion_gdscript_builtin("\tmtx.lock()", "\tmtx.lock()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
894
valid = valid && test_conversion_gdscript_builtin("\tmutex.unlock()", "\tmutex.unlock()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
895
896
valid = valid && test_conversion_with_regex("extends CSGBox", "extends CSGBox3D", &ProjectConverter3To4::rename_classes, "classes", reg_container);
897
valid = valid && test_conversion_with_regex("CSGBox", "CSGBox3D", &ProjectConverter3To4::rename_classes, "classes", reg_container);
898
valid = valid && test_conversion_with_regex("Spatial", "Node3D", &ProjectConverter3To4::rename_classes, "classes", reg_container);
899
valid = valid && test_conversion_with_regex("Spatial.tscn", "Spatial.tscn", &ProjectConverter3To4::rename_classes, "classes", reg_container);
900
valid = valid && test_conversion_with_regex("Spatial.gd", "Spatial.gd", &ProjectConverter3To4::rename_classes, "classes", reg_container);
901
valid = valid && test_conversion_with_regex("Spatial.shader", "Spatial.shader", &ProjectConverter3To4::rename_classes, "classes", reg_container);
902
valid = valid && test_conversion_with_regex("Spatial.other", "Node3D.other", &ProjectConverter3To4::rename_classes, "classes", reg_container);
903
904
valid = valid && test_conversion_gdscript_builtin("\nonready", "\n@onready", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container, false);
905
valid = valid && test_conversion_gdscript_builtin("onready", "@onready", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container, false);
906
valid = valid && test_conversion_gdscript_builtin(" onready", " onready", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container, false);
907
valid = valid && test_conversion_gdscript_builtin("\nexport", "\n@export", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container, false);
908
valid = valid && test_conversion_gdscript_builtin("\texport", "\t@export", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container, false);
909
valid = valid && test_conversion_gdscript_builtin("\texport_dialog", "\texport_dialog", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container, false);
910
valid = valid && test_conversion_gdscript_builtin("export", "@export", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container, false);
911
valid = valid && test_conversion_gdscript_builtin(" export", " export", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container, false);
912
valid = valid && test_conversion_gdscript_builtin("\n\nremote func", "\n\n@rpc(\"any_peer\") func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container, false);
913
valid = valid && test_conversion_gdscript_builtin("\n\nremote func", "\n\n@rpc(\\\"any_peer\\\") func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container, true);
914
valid = valid && test_conversion_gdscript_builtin("\n\nremotesync func", "\n\n@rpc(\"any_peer\", \"call_local\") func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container, false);
915
valid = valid && test_conversion_gdscript_builtin("\n\nremotesync func", "\n\n@rpc(\\\"any_peer\\\", \\\"call_local\\\") func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container, true);
916
valid = valid && test_conversion_gdscript_builtin("\n\nsync func", "\n\n@rpc(\"any_peer\", \"call_local\") func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container, false);
917
valid = valid && test_conversion_gdscript_builtin("\n\nsync func", "\n\n@rpc(\\\"any_peer\\\", \\\"call_local\\\") func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container, true);
918
valid = valid && test_conversion_gdscript_builtin("\n\nslave func", "\n\n@rpc func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container, false);
919
valid = valid && test_conversion_gdscript_builtin("\n\npuppet func", "\n\n@rpc func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container, false);
920
valid = valid && test_conversion_gdscript_builtin("\n\npuppetsync func", "\n\n@rpc(\"call_local\") func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container, false);
921
valid = valid && test_conversion_gdscript_builtin("\n\npuppetsync func", "\n\n@rpc(\\\"call_local\\\") func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container, true);
922
valid = valid && test_conversion_gdscript_builtin("\n\nmaster func", "\n\nThe master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using get_multiplayer().get_remote_sender_id()\n@rpc func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container, false);
923
valid = valid && test_conversion_gdscript_builtin("\n\nmastersync func", "\n\nThe master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using get_multiplayer().get_remote_sender_id()\n@rpc(\"call_local\") func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container, false);
924
925
valid = valid && test_conversion_gdscript_builtin("var size: Vector2 = Vector2() setget set_function, get_function", "var size: Vector2 = Vector2(): get = get_function, set = set_function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
926
valid = valid && test_conversion_gdscript_builtin("var size: Vector2 = Vector2() setget set_function, ", "var size: Vector2 = Vector2(): set = set_function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
927
valid = valid && test_conversion_gdscript_builtin("var size: Vector2 = Vector2() setget set_function", "var size: Vector2 = Vector2(): set = set_function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
928
valid = valid && test_conversion_gdscript_builtin("var size: Vector2 = Vector2() setget , get_function", "var size: Vector2 = Vector2(): get = get_function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
929
930
valid = valid && test_conversion_gdscript_builtin("get_node(@", "get_node(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
931
932
valid = valid && test_conversion_gdscript_builtin("yield(this, \"timeout\")", "await this.timeout", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
933
valid = valid && test_conversion_gdscript_builtin("yield(this, \\\"timeout\\\")", "await this.timeout", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, true);
934
935
valid = valid && test_conversion_gdscript_builtin(" Transform.xform(Vector3(a,b,c) + Vector3.UP) ", " Transform * (Vector3(a,b,c) + Vector3.UP) ", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
936
valid = valid && test_conversion_gdscript_builtin(" Transform.xform_inv(Vector3(a,b,c) + Vector3.UP) ", " (Vector3(a,b,c) + Vector3.UP) * Transform ", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
937
938
valid = valid && test_conversion_gdscript_builtin("export(float) var lifetime = 3.0", "export var lifetime: float = 3.0", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
939
valid = valid && test_conversion_gdscript_builtin("export (int)var spaces=1", "export var spaces: int=1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
940
valid = valid && test_conversion_gdscript_builtin("export(String, 'AnonymousPro', 'CourierPrime') var _font_name = 'AnonymousPro'", "export var _font_name = 'AnonymousPro' # (String, 'AnonymousPro', 'CourierPrime')", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); // TODO, this is only a workaround
941
valid = valid && test_conversion_gdscript_builtin("export(PackedScene) var mob_scene", "export var mob_scene: PackedScene", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
942
valid = valid && test_conversion_gdscript_builtin("export(float) var lifetime: float = 3.0", "export var lifetime: float = 3.0", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
943
valid = valid && test_conversion_gdscript_builtin("export var lifetime: float = 3.0", "export var lifetime: float = 3.0", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
944
valid = valid && test_conversion_gdscript_builtin("export var lifetime := 3.0", "export var lifetime := 3.0", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
945
valid = valid && test_conversion_gdscript_builtin("export(float) var lifetime := 3.0", "export var lifetime := 3.0", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
946
947
valid = valid && test_conversion_gdscript_builtin("var d = parse_json(roman(sfs))", "var test_json_conv = JSON.new()\ntest_json_conv.parse(roman(sfs))\nvar d = test_json_conv.get_data()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
948
949
valid = valid && test_conversion_gdscript_builtin("to_json( AA ) szon", "JSON.new().stringify( AA ) szon", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
950
valid = valid && test_conversion_gdscript_builtin("s to_json", "s JSON.new().stringify", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
951
valid = valid && test_conversion_gdscript_builtin("AF to_json2", "AF to_json2", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
952
valid = valid && test_conversion_gdscript_builtin("var rr = JSON.parse(a)", "var test_json_conv = JSON.new()\ntest_json_conv.parse(a)\nvar rr = test_json_conv.get_data()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
953
954
valid = valid && test_conversion_gdscript_builtin("empty()", "is_empty()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
955
valid = valid && test_conversion_gdscript_builtin(".empty", ".empty", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
956
957
valid = valid && test_conversion_gdscript_builtin(").roman(", ").roman(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
958
valid = valid && test_conversion_gdscript_builtin("\t.roman(", "\tsuper.roman(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
959
valid = valid && test_conversion_gdscript_builtin(" .roman(", " super.roman(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
960
valid = valid && test_conversion_gdscript_builtin(".1", ".1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
961
valid = valid && test_conversion_gdscript_builtin(" .1", " .1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
962
valid = valid && test_conversion_gdscript_builtin("'.'", "'.'", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
963
valid = valid && test_conversion_gdscript_builtin("'.a'", "'.a'", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
964
valid = valid && test_conversion_gdscript_builtin("\t._input(_event)", "\tsuper._input(_event)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
965
966
valid = valid && test_conversion_gdscript_builtin("(connect(A,B,C) != OK):", "(connect(A, Callable(B, C)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
967
valid = valid && test_conversion_gdscript_builtin("(connect(A,B,C,D) != OK):", "(connect(A, Callable(B, C).bind(D)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
968
valid = valid && test_conversion_gdscript_builtin("(connect(A,B,C,[D]) != OK):", "(connect(A, Callable(B, C).bind(D)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
969
valid = valid && test_conversion_gdscript_builtin("(connect(A,B,C,[D,E]) != OK):", "(connect(A, Callable(B, C).bind(D,E)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
970
valid = valid && test_conversion_gdscript_builtin("(connect(A,B,C,[D,E],F) != OK):", "(connect(A, Callable(B, C).bind(D,E), F) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
971
valid = valid && test_conversion_gdscript_builtin("(connect(A,B,C,D,E) != OK):", "(connect(A, Callable(B, C).bind(D), E) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
972
973
valid = valid && test_conversion_gdscript_builtin(".connect(A,B,C)", ".connect(A, Callable(B, C))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
974
valid = valid && test_conversion_gdscript_builtin("abc.connect(A,B,C)", "abc.connect(A, Callable(B, C))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
975
valid = valid && test_conversion_gdscript_builtin("\tconnect(A,B,C)", "\tconnect(A, Callable(B, C))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
976
valid = valid && test_conversion_gdscript_builtin(" connect(A,B,C)", " connect(A, Callable(B, C))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
977
valid = valid && test_conversion_gdscript_builtin("_connect(A,B,C)", "_connect(A,B,C)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
978
valid = valid && test_conversion_gdscript_builtin("do_connect(A,B,C)", "do_connect(A,B,C)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
979
valid = valid && test_conversion_gdscript_builtin("$connect(A,B,C)", "$connect(A,B,C)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
980
valid = valid && test_conversion_gdscript_builtin("@connect(A,B,C)", "@connect(A,B,C)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
981
982
valid = valid && test_conversion_gdscript_builtin("(start(A,B) != OK):", "(start(Callable(A, B)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
983
valid = valid && test_conversion_gdscript_builtin("func start(A,B):", "func start(A,B):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
984
valid = valid && test_conversion_gdscript_builtin("(start(A,B,C,D,E,F,G) != OK):", "(start(Callable(A, B).bind(C), D, E, F, G) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
985
valid = valid && test_conversion_gdscript_builtin("disconnect(A,B,C) != OK):", "disconnect(A, Callable(B, C)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
986
valid = valid && test_conversion_gdscript_builtin("is_connected(A,B,C) != OK):", "is_connected(A, Callable(B, C)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
987
valid = valid && test_conversion_gdscript_builtin("is_connected(A,B,C))", "is_connected(A, Callable(B, C)))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
988
989
valid = valid && test_conversion_gdscript_builtin("(tween_method(A,B,C,D,E).foo())", "(tween_method(Callable(A, B), C, D, E).foo())", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
990
valid = valid && test_conversion_gdscript_builtin("(tween_method(A,B,C,D,E,[F,G]).foo())", "(tween_method(Callable(A, B).bind(F,G), C, D, E).foo())", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
991
valid = valid && test_conversion_gdscript_builtin("(tween_callback(A,B).foo())", "(tween_callback(Callable(A, B)).foo())", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
992
valid = valid && test_conversion_gdscript_builtin("(tween_callback(A,B,[C,D]).foo())", "(tween_callback(Callable(A, B).bind(C,D)).foo())", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
993
994
valid = valid && test_conversion_gdscript_builtin("func _init(", "func _init(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
995
valid = valid && test_conversion_gdscript_builtin("func _init(a,b,c).(d,e,f):", "func _init(a,b,c):\n\tsuper(d,e,f)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
996
valid = valid && test_conversion_gdscript_builtin("func _init(a,b,c).(a.b(),c.d()):", "func _init(a,b,c):\n\tsuper(a.b(),c.d())", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
997
valid = valid && test_conversion_gdscript_builtin("func _init(p_x:int)->void:", "func _init(p_x:int)->void:", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
998
valid = valid && test_conversion_gdscript_builtin("func _init(a: int).(d,e,f) -> void:", "func _init(a: int) -> void:\n\tsuper(d,e,f)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
999
valid = valid && test_conversion_gdscript_builtin("q_PackedDataContainer._iter_init(variable1)", "q_PackedDataContainer._iter_init(variable1)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
1000
1001
valid = valid && test_conversion_gdscript_builtin("create_from_image(aa, bb)", "create_from_image(aa) #,bb", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
1002
valid = valid && test_conversion_gdscript_builtin("q_ImageTexture.create_from_image(variable1, variable2)", "q_ImageTexture.create_from_image(variable1) #,variable2", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
1003
1004
valid = valid && test_conversion_gdscript_builtin("set_cell_item(a, b, c, d ,e) # AA", "set_cell_item(Vector3(a, b, c), d, e) # AA", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
1005
valid = valid && test_conversion_gdscript_builtin("set_cell_item(a, b)", "set_cell_item(a, b)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
1006
valid = valid && test_conversion_gdscript_builtin("get_cell_item_orientation(a, b,c)", "get_cell_item_orientation(Vector3i(a, b, c))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
1007
valid = valid && test_conversion_gdscript_builtin("get_cell_item(a, b,c)", "get_cell_item(Vector3i(a, b, c))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
1008
valid = valid && test_conversion_gdscript_builtin("map_to_world(a, b,c)", "map_to_local(Vector3i(a, b, c))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
1009
1010
valid = valid && test_conversion_gdscript_builtin("PackedStringArray(req_godot).join('.')", "'.'.join(PackedStringArray(req_godot))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
1011
valid = valid && test_conversion_gdscript_builtin("=PackedStringArray(req_godot).join('.')", "='.'.join(PackedStringArray(req_godot))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
1012
1013
valid = valid && test_conversion_gdscript_builtin("apply_force(position, impulse)", "apply_force(impulse, position)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
1014
valid = valid && test_conversion_gdscript_builtin("apply_impulse(position, impulse)", "apply_impulse(impulse, position)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
1015
valid = valid && test_conversion_gdscript_builtin("draw_rect(a,b,c,d,e).abc", "draw_rect(a, b, c, d).abc# e) TODOConverter3To4 Antialiasing argument is missing", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
1016
valid = valid && test_conversion_gdscript_builtin("get_focus_owner()", "get_viewport().gui_get_focus_owner()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
1017
valid = valid && test_conversion_gdscript_builtin("button.pressed = 1", "button.button_pressed = 1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
1018
valid = valid && test_conversion_gdscript_builtin("button.pressed=1", "button.button_pressed=1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
1019
valid = valid && test_conversion_gdscript_builtin("button.pressed SF", "button.pressed SF", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
1020
1021
valid = valid && test_conversion_with_regex("Color(\"#f47d\")", "Color(\"#47df\")", &ProjectConverter3To4::convert_hexadecimal_colors, "color literals", reg_container);
1022
valid = valid && test_conversion_with_regex("Color(\"#ff478cbf\")", "Color(\"#478cbfff\")", &ProjectConverter3To4::convert_hexadecimal_colors, "color literals", reg_container);
1023
valid = valid && test_conversion_with_regex("Color(\"#de32bf\")", "Color(\"#de32bf\")", &ProjectConverter3To4::convert_hexadecimal_colors, "color literals", reg_container);
1024
valid = valid && test_conversion_with_regex("AAA Color.white AF", "AAA Color.WHITE AF", &ProjectConverter3To4::rename_colors, "color constants", reg_container);
1025
1026
// Note: Do not change to *scancode*, it is applied before that conversion.
1027
valid = valid && test_conversion_with_regex("\"device\":-1,\"scancode\":16777231,\"physical_scancode\":16777232", "\"device\":-1,\"scancode\":4194319,\"physical_scancode\":4194320", &ProjectConverter3To4::rename_input_map_scancode, "custom rename", reg_container);
1028
valid = valid && test_conversion_with_regex("\"device\":-1,\"scancode\":65,\"physical_scancode\":66", "\"device\":-1,\"scancode\":65,\"physical_scancode\":66", &ProjectConverter3To4::rename_input_map_scancode, "custom rename", reg_container);
1029
1030
valid = valid && test_conversion_with_regex("\"device\":0,\"button_index\":5,\"pressure\":0.0,\"pressed\":false,", "\"device\":0,\"button_index\":10,\"pressure\":0.0,\"pressed\":false,", &ProjectConverter3To4::rename_joypad_buttons_and_axes, "custom rename", reg_container);
1031
valid = valid && test_conversion_with_regex("\"device\":0,\"axis\":6,", "\"device\":0,\"axis\":4,", &ProjectConverter3To4::rename_joypad_buttons_and_axes, "custom rename", reg_container);
1032
valid = valid && test_conversion_with_regex("InputEventJoypadButton,\"button_index\":7,\"pressure\":0.0,\"pressed\":false,\"script\":null", "InputEventJoypadMotion,\"axis\":5,\"axis_value\":1.0,\"script\":null", &ProjectConverter3To4::rename_joypad_buttons_and_axes, "custom rename", reg_container);
1033
1034
// Custom rule conversion
1035
{
1036
String from = "instance";
1037
String to = "instantiate";
1038
String name = "AA.instance()";
1039
1040
Vector<SourceLine> got = split_lines(name);
1041
1042
String expected = "AA.instantiate()";
1043
custom_rename(got, from, to);
1044
String got_str = collect_string_from_vector(got);
1045
if (got_str != expected) {
1046
ERR_PRINT(vformat("Failed to convert custom rename \"%s\" to \"%s\", got \"%s\", instead.", name, expected, got_str));
1047
}
1048
valid = valid && (got_str == expected);
1049
}
1050
1051
// get_object_of_execution
1052
{
1053
String base = "var roman = kieliszek.";
1054
String expected = "kieliszek.";
1055
String got = get_object_of_execution(base);
1056
if (got != expected) {
1057
ERR_PRINT(vformat("Failed to get proper data from get_object_of_execution. \"%s\" should return \"%s\"(%d), got \"%s\"(%d), instead.", base, expected, expected.size(), got, got.size()));
1058
}
1059
valid = valid && (got == expected);
1060
}
1061
{
1062
String base = "r.";
1063
String expected = "r.";
1064
String got = get_object_of_execution(base);
1065
if (got != expected) {
1066
ERR_PRINT(vformat("Failed to get proper data from get_object_of_execution. \"%s\" should return \"%s\"(%d), got \"%s\"(%d), instead.", base, expected, expected.size(), got, got.size()));
1067
}
1068
valid = valid && (got == expected);
1069
}
1070
{
1071
String base = "mortadela(";
1072
String expected = "";
1073
String got = get_object_of_execution(base);
1074
if (got != expected) {
1075
ERR_PRINT(vformat("Failed to get proper data from get_object_of_execution. \"%s\" should return \"%s\"(%d), got \"%s\"(%d), instead.", base, expected, expected.size(), got, got.size()));
1076
}
1077
valid = valid && (got == expected);
1078
}
1079
{
1080
String base = "var node = $world/ukraine/lviv.";
1081
String expected = "$world/ukraine/lviv.";
1082
String got = get_object_of_execution(base);
1083
if (got != expected) {
1084
ERR_PRINT(vformat("Failed to get proper data from get_object_of_execution. \"%s\" should return \"%s\"(%d), got \"%s\"(%d), instead.", base, expected, expected.size(), got, got.size()));
1085
}
1086
valid = valid && (got == expected);
1087
}
1088
1089
// get_starting_space
1090
{
1091
String base = "\t\t\t var roman = kieliszek.";
1092
String expected = "\t\t\t";
1093
String got = get_starting_space(base);
1094
if (got != expected) {
1095
ERR_PRINT(vformat("Failed to get proper data from get_object_of_execution. \"%s\" should return \"%s\"(%d), got \"%s\"(%d), instead.", base, expected, expected.size(), got, got.size()));
1096
}
1097
valid = valid && (got == expected);
1098
}
1099
1100
// Parse Arguments
1101
{
1102
String line = "( )";
1103
Vector<String> got_vector = parse_arguments(line);
1104
String got = "";
1105
String expected = "";
1106
for (String &part : got_vector) {
1107
got += part + "|||";
1108
}
1109
if (got != expected) {
1110
ERR_PRINT(vformat("Failed to get proper data from parse_arguments. \"%s\" should return \"%s\"(%d), got \"%s\"(%d), instead.", line, expected, expected.size(), got, got.size()));
1111
}
1112
valid = valid && (got == expected);
1113
}
1114
{
1115
String line = "(a , b , c)";
1116
Vector<String> got_vector = parse_arguments(line);
1117
String got = "";
1118
String expected = "a|||b|||c|||";
1119
for (String &part : got_vector) {
1120
got += part + "|||";
1121
}
1122
if (got != expected) {
1123
ERR_PRINT(vformat("Failed to get proper data from parse_arguments. \"%s\" should return \"%s\"(%d), got \"%s\"(%d), instead.", line, expected, expected.size(), got, got.size()));
1124
}
1125
valid = valid && (got == expected);
1126
}
1127
{
1128
String line = "(a , \"b,\" , c)";
1129
Vector<String> got_vector = parse_arguments(line);
1130
String got = "";
1131
String expected = "a|||\"b,\"|||c|||";
1132
for (String &part : got_vector) {
1133
got += part + "|||";
1134
}
1135
if (got != expected) {
1136
ERR_PRINT(vformat("Failed to get proper data from parse_arguments. \"%s\" should return \"%s\"(%d), got \"%s\"(%d), instead.", line, expected, expected.size(), got, got.size()));
1137
}
1138
valid = valid && (got == expected);
1139
}
1140
{
1141
String line = "(a , \"(,),,,,\" , c)";
1142
Vector<String> got_vector = parse_arguments(line);
1143
String got = "";
1144
String expected = "a|||\"(,),,,,\"|||c|||";
1145
for (String &part : got_vector) {
1146
got += part + "|||";
1147
}
1148
if (got != expected) {
1149
ERR_PRINT(vformat("Failed to get proper data from parse_arguments. \"%s\" should return \"%s\"(%d), got \"%s\"(%d), instead.", line, expected, expected.size(), got, got.size()));
1150
}
1151
valid = valid && (got == expected);
1152
}
1153
1154
return valid;
1155
}
1156
1157
// Validate in all arrays if names don't do cyclic renames "Node" -> "Node2D" | "Node2D" -> "2DNode"
1158
bool ProjectConverter3To4::test_array_names() {
1159
bool valid = true;
1160
Vector<String> names = Vector<String>();
1161
1162
// Validate if all classes are valid.
1163
{
1164
for (unsigned int current_index = 0; RenamesMap3To4::class_renames[current_index][0]; current_index++) {
1165
const String old_class = RenamesMap3To4::class_renames[current_index][0];
1166
const String new_class = RenamesMap3To4::class_renames[current_index][1];
1167
1168
// Light2D, Texture, Viewport are special classes(probably virtual ones).
1169
if (ClassDB::class_exists(StringName(old_class)) && old_class != "Light2D" && old_class != "Texture" && old_class != "Viewport") {
1170
ERR_PRINT(vformat("Class \"%s\" exists in Godot 4, so it cannot be renamed to something else.", old_class));
1171
valid = false; // This probably should be only a warning, but not 100% sure - this would need to be added to CI.
1172
}
1173
1174
// Callable is special class, to which normal classes may be renamed.
1175
if (!ClassDB::class_exists(StringName(new_class)) && new_class != "Callable") {
1176
ERR_PRINT(vformat("Class \"%s\" does not exist in Godot 4, so it cannot be used in the conversion.", new_class));
1177
valid = false; // This probably should be only a warning, but not 100% sure - this would need to be added to CI.
1178
}
1179
}
1180
}
1181
1182
{
1183
HashSet<String> all_functions;
1184
1185
// List of excluded functions from builtin types and global namespace, because currently it is not possible to get list of functions from them.
1186
// This will be available when https://github.com/godotengine/godot/pull/49053 or similar will be included into Godot.
1187
static const char *builtin_types_excluded_functions[] = { "dict_to_inst", "inst_to_dict", "bytes_to_var", "bytes_to_var_with_objects", "db_to_linear", "deg_to_rad", "linear_to_db", "rad_to_deg", "randf_range", "snapped", "str_to_var", "var_to_str", "var_to_bytes", "var_to_bytes_with_objects", "move_toward", "uri_encode", "uri_decode", "remove_at", "get_rotation_quaternion", "limit_length", "grow_side", "is_absolute_path", "is_valid_int", "lerp", "to_ascii_buffer", "to_utf8_buffer", "to_utf32_buffer", "to_wchar_buffer", "snapped", "remap", "rfind", nullptr };
1188
for (int current_index = 0; builtin_types_excluded_functions[current_index]; current_index++) {
1189
all_functions.insert(builtin_types_excluded_functions[current_index]);
1190
}
1191
1192
//for (int type = Variant::Type::NIL + 1; type < Variant::Type::VARIANT_MAX; type++) {
1193
// List<MethodInfo> method_list;
1194
// Variant::get_method_list_by_type(&method_list, Variant::Type(type));
1195
// for (MethodInfo &function_data : method_list) {
1196
// if (!all_functions.has(function_data.name)) {
1197
// all_functions.insert(function_data.name);
1198
// }
1199
// }
1200
//}
1201
1202
LocalVector<StringName> classes_list;
1203
ClassDB::get_class_list(classes_list);
1204
for (StringName &name_of_class : classes_list) {
1205
List<MethodInfo> method_list;
1206
ClassDB::get_method_list(name_of_class, &method_list, true);
1207
for (MethodInfo &function_data : method_list) {
1208
if (!all_functions.has(function_data.name)) {
1209
all_functions.insert(function_data.name);
1210
}
1211
}
1212
}
1213
1214
int current_element = 0;
1215
while (RenamesMap3To4::gdscript_function_renames[current_element][0] != nullptr) {
1216
String name_3_x = RenamesMap3To4::gdscript_function_renames[current_element][0];
1217
String name_4_0 = RenamesMap3To4::gdscript_function_renames[current_element][1];
1218
if (!all_functions.has(name_4_0)) {
1219
ERR_PRINT(vformat("Missing GDScript function in pair (%s - ===> %s <===)", name_3_x, name_4_0));
1220
valid = false;
1221
}
1222
current_element++;
1223
}
1224
}
1225
if (!valid) {
1226
ERR_PRINT("Found function which is used in the converter, but it cannot be found in Godot 4. Rename this element or remove its entry if it's obsolete.");
1227
}
1228
1229
valid = valid && test_single_array(RenamesMap3To4::enum_renames);
1230
valid = valid && test_single_array(RenamesMap3To4::class_renames, true);
1231
valid = valid && test_single_array(RenamesMap3To4::gdscript_function_renames, true);
1232
valid = valid && test_single_array(RenamesMap3To4::csharp_function_renames, true);
1233
valid = valid && test_single_array(RenamesMap3To4::gdscript_properties_renames, true);
1234
valid = valid && test_single_array(RenamesMap3To4::csharp_properties_renames, true);
1235
valid = valid && test_single_array(RenamesMap3To4::shaders_renames, true);
1236
valid = valid && test_single_array(RenamesMap3To4::gdscript_signals_renames);
1237
valid = valid && test_single_array(RenamesMap3To4::project_settings_renames);
1238
valid = valid && test_single_array(RenamesMap3To4::project_godot_renames);
1239
valid = valid && test_single_array(RenamesMap3To4::input_map_renames);
1240
valid = valid && test_single_array(RenamesMap3To4::builtin_types_renames);
1241
valid = valid && test_single_array(RenamesMap3To4::color_renames);
1242
1243
return valid;
1244
}
1245
1246
// Validates the array to prevent cyclic renames, such as `Node` -> `Node2D`, then `Node2D` -> `2DNode`.
1247
// Also checks if names contain leading or trailing spaces.
1248
bool ProjectConverter3To4::test_single_array(const char *p_array[][2], bool p_ignore_4_0_name) {
1249
bool valid = true;
1250
Vector<String> names = Vector<String>();
1251
1252
for (unsigned int current_index = 0; p_array[current_index][0]; current_index++) {
1253
String name_3_x = p_array[current_index][0];
1254
String name_4_0 = p_array[current_index][1];
1255
if (name_3_x != name_3_x.strip_edges()) {
1256
ERR_PRINT(vformat("Invalid Entry \"%s\" contains leading or trailing spaces.", name_3_x));
1257
valid = false;
1258
}
1259
if (names.has(name_3_x)) {
1260
ERR_PRINT(vformat("Found duplicated entry, pair ( -> %s , %s)", name_3_x, name_4_0));
1261
valid = false;
1262
}
1263
names.append(name_3_x);
1264
1265
if (name_4_0 != name_4_0.strip_edges()) {
1266
ERR_PRINT(vformat("Invalid Entry \"%s\" contains leading or trailing spaces.", name_3_x));
1267
valid = false;
1268
}
1269
if (names.has(name_4_0)) {
1270
ERR_PRINT(vformat("Found duplicated entry, pair ( -> %s , %s)", name_3_x, name_4_0));
1271
valid = false;
1272
}
1273
if (!p_ignore_4_0_name) {
1274
names.append(name_4_0);
1275
}
1276
}
1277
return valid;
1278
}
1279
1280
// Returns arguments from given function execution, this cannot be really done as regex.
1281
// `abc(d,e(f,g),h)` -> [d], [e(f,g)], [h]
1282
Vector<String> ProjectConverter3To4::parse_arguments(const String &line) {
1283
Vector<String> parts;
1284
int string_size = line.length();
1285
int start_part = 0; // Index of beginning of start part.
1286
int parts_counter = 0;
1287
char32_t previous_character = '\0';
1288
bool is_inside_string = false; // If true, it ignores these 3 characters ( , ) inside string.
1289
1290
ERR_FAIL_COND_V_MSG(line.count("(") != line.count(")"), parts, vformat("Converter internal bug: substring should have equal number of open and close parentheses in line - \"%s\".", line));
1291
1292
for (int current_index = 0; current_index < string_size; current_index++) {
1293
char32_t character = line.get(current_index);
1294
switch (character) {
1295
case '(':
1296
case '[':
1297
case '{': {
1298
parts_counter++;
1299
if (parts_counter == 1 && !is_inside_string) {
1300
start_part = current_index;
1301
}
1302
break;
1303
};
1304
case ')':
1305
case '}': {
1306
parts_counter--;
1307
if (parts_counter == 0 && !is_inside_string) {
1308
parts.append(line.substr(start_part + 1, current_index - start_part - 1));
1309
start_part = current_index;
1310
}
1311
break;
1312
};
1313
case ']': {
1314
parts_counter--;
1315
if (parts_counter == 0 && !is_inside_string) {
1316
parts.append(line.substr(start_part, current_index - start_part));
1317
start_part = current_index;
1318
}
1319
break;
1320
};
1321
case ',': {
1322
if (parts_counter == 1 && !is_inside_string) {
1323
parts.append(line.substr(start_part + 1, current_index - start_part - 1));
1324
start_part = current_index;
1325
}
1326
break;
1327
};
1328
case '"': {
1329
if (previous_character != '\\') {
1330
is_inside_string = !is_inside_string;
1331
}
1332
}
1333
}
1334
previous_character = character;
1335
}
1336
1337
Vector<String> clean_parts;
1338
for (String &part : parts) {
1339
part = part.strip_edges();
1340
if (!part.is_empty()) {
1341
clean_parts.append(part);
1342
}
1343
}
1344
1345
return clean_parts;
1346
}
1347
1348
// Finds latest parenthesis owned by function.
1349
// `function(abc(a,b),DD)):` finds this parenthess `function(abc(a,b),DD => ) <= ):`
1350
int ProjectConverter3To4::get_end_parenthesis(const String &line) const {
1351
int current_state = 0;
1352
for (int current_index = 0; line.length() > current_index; current_index++) {
1353
char32_t character = line.get(current_index);
1354
if (character == '(') {
1355
current_state++;
1356
}
1357
if (character == ')') {
1358
current_state--;
1359
if (current_state == 0) {
1360
return current_index;
1361
}
1362
}
1363
}
1364
return -1;
1365
}
1366
1367
// Merges multiple arguments into a single String.
1368
// Needed when after processing e.g. 2 arguments, later arguments are not changed in any way.
1369
String ProjectConverter3To4::connect_arguments(const Vector<String> &arguments, int from, int to) const {
1370
if (to == -1) {
1371
to = arguments.size();
1372
}
1373
1374
String value;
1375
if (arguments.size() > 0 && from != 0 && from < to) {
1376
value = ", ";
1377
}
1378
1379
for (int i = from; i < to; i++) {
1380
value += arguments[i];
1381
if (i != to - 1) {
1382
value += ", ";
1383
}
1384
}
1385
return value;
1386
}
1387
1388
// Returns the indentation (spaces and tabs) at the start of the line e.g. `\t\tmove_this` returns `\t\t`.
1389
String ProjectConverter3To4::get_starting_space(const String &line) const {
1390
String empty_space;
1391
int current_character = 0;
1392
1393
if (line.is_empty()) {
1394
return empty_space;
1395
}
1396
1397
if (line[0] == ' ') {
1398
while (current_character < line.size()) {
1399
if (line[current_character] == ' ') {
1400
empty_space += ' ';
1401
current_character++;
1402
} else {
1403
break;
1404
}
1405
}
1406
}
1407
if (line[0] == '\t') {
1408
while (current_character < line.size()) {
1409
if (line[current_character] == '\t') {
1410
empty_space += '\t';
1411
current_character++;
1412
} else {
1413
break;
1414
}
1415
}
1416
}
1417
return empty_space;
1418
}
1419
1420
// Returns the object that’s executing the function in the line.
1421
// e.g. Passing the line "var roman = kieliszek.funkcja()" to this function returns "kieliszek".
1422
String ProjectConverter3To4::get_object_of_execution(const String &line) const {
1423
int end = line.size() - 1; // Last one is \0
1424
int variable_start = end - 1;
1425
int start = end - 1;
1426
1427
bool is_possibly_nodepath = false;
1428
bool is_valid_nodepath = false;
1429
1430
while (start >= 0) {
1431
char32_t character = line[start];
1432
bool is_variable_char = (character >= 'A' && character <= 'Z') || (character >= 'a' && character <= 'z') || character == '.' || character == '_';
1433
bool is_nodepath_start = character == '$';
1434
bool is_nodepath_sep = character == '/';
1435
if (is_variable_char || is_nodepath_start || is_nodepath_sep) {
1436
if (start == 0) {
1437
break;
1438
} else if (is_nodepath_sep) {
1439
// Freeze variable_start, try to fetch more chars since this might be a Node path literal.
1440
is_possibly_nodepath = true;
1441
} else if (is_nodepath_start) {
1442
// Found $, this is a Node path literal.
1443
is_valid_nodepath = true;
1444
break;
1445
}
1446
if (!is_possibly_nodepath) {
1447
variable_start--;
1448
}
1449
start--;
1450
continue;
1451
} else {
1452
// Abandon all hope, this is neither a variable nor a Node path literal.
1453
variable_start++; // Found invalid character, needs to be ignored.
1454
break;
1455
}
1456
}
1457
if (is_valid_nodepath) {
1458
variable_start = start;
1459
}
1460
return line.substr(variable_start, (end - variable_start));
1461
}
1462
1463
void ProjectConverter3To4::rename_colors(Vector<SourceLine> &source_lines, const RegExContainer &reg_container) {
1464
for (SourceLine &source_line : source_lines) {
1465
if (source_line.is_comment) {
1466
continue;
1467
}
1468
1469
String &line = source_line.line;
1470
if (uint64_t(line.length()) <= maximum_line_length) {
1471
if (line.contains("Color.")) {
1472
for (unsigned int current_index = 0; RenamesMap3To4::color_renames[current_index][0]; current_index++) {
1473
line = reg_container.color_regexes[current_index]->sub(line, reg_container.color_renamed[current_index], true);
1474
}
1475
}
1476
}
1477
}
1478
}
1479
1480
// Convert hexadecimal colors from ARGB to RGBA
1481
void ProjectConverter3To4::convert_hexadecimal_colors(Vector<SourceLine> &source_lines, const RegExContainer &reg_container) {
1482
for (SourceLine &source_line : source_lines) {
1483
if (source_line.is_comment) {
1484
continue;
1485
}
1486
1487
String &line = source_line.line;
1488
if (uint64_t(line.length()) <= maximum_line_length) {
1489
if (line.contains("Color(\"")) {
1490
line = reg_container.color_hexadecimal_short_constructor.sub(line, "Color(\"#$2$1", true);
1491
line = reg_container.color_hexadecimal_full_constructor.sub(line, "Color(\"#$2$1", true);
1492
}
1493
}
1494
}
1495
}
1496
1497
Vector<String> ProjectConverter3To4::check_for_rename_colors(Vector<String> &lines, const RegExContainer &reg_container) {
1498
Vector<String> found_renames;
1499
1500
int current_line = 1;
1501
for (String &line : lines) {
1502
if (uint64_t(line.length()) <= maximum_line_length) {
1503
if (line.contains("Color.")) {
1504
for (unsigned int current_index = 0; RenamesMap3To4::color_renames[current_index][0]; current_index++) {
1505
TypedArray<RegExMatch> reg_match = reg_container.color_regexes[current_index]->search_all(line);
1506
if (reg_match.size() > 0) {
1507
found_renames.append(line_formatter(current_line, RenamesMap3To4::color_renames[current_index][0], RenamesMap3To4::color_renames[current_index][1], line));
1508
}
1509
}
1510
}
1511
}
1512
current_line++;
1513
}
1514
1515
return found_renames;
1516
}
1517
1518
void ProjectConverter3To4::fix_tool_declaration(Vector<SourceLine> &source_lines, const RegExContainer &reg_container) {
1519
// In godot4, "tool" became "@tool" and must be located at the top of the file.
1520
for (int i = 0; i < source_lines.size(); ++i) {
1521
if (source_lines[i].line == "tool") {
1522
source_lines.remove_at(i);
1523
source_lines.insert(0, { "@tool", false });
1524
return; // assuming there's at most 1 tool declaration.
1525
}
1526
}
1527
}
1528
1529
void ProjectConverter3To4::fix_pause_mode(Vector<SourceLine> &source_lines, const RegExContainer &reg_container) {
1530
// In Godot 3, the pause_mode 2 equals the PAUSE_MODE_PROCESS value.
1531
// In Godot 4, the pause_mode PAUSE_MODE_PROCESS was renamed to PROCESS_MODE_ALWAYS and equals the number 3.
1532
// We therefore convert pause_mode = 2 to pause_mode = 3.
1533
for (SourceLine &source_line : source_lines) {
1534
String &line = source_line.line;
1535
1536
if (line == "pause_mode = 2") {
1537
// Note: pause_mode is renamed to process_mode later on, so no need to do it here.
1538
line = "pause_mode = 3";
1539
}
1540
}
1541
}
1542
1543
void ProjectConverter3To4::rename_classes(Vector<SourceLine> &source_lines, const RegExContainer &reg_container) {
1544
for (SourceLine &source_line : source_lines) {
1545
if (source_line.is_comment) {
1546
continue;
1547
}
1548
1549
String &line = source_line.line;
1550
if (uint64_t(line.length()) <= maximum_line_length) {
1551
for (unsigned int current_index = 0; RenamesMap3To4::class_renames[current_index][0]; current_index++) {
1552
if (line.contains(RenamesMap3To4::class_renames[current_index][0])) {
1553
bool found_ignored_items = false;
1554
// Renaming Spatial.tscn to TEMP_RENAMED_CLASS.tscn.
1555
if (line.contains(String(RenamesMap3To4::class_renames[current_index][0]) + ".")) {
1556
found_ignored_items = true;
1557
line = reg_container.class_tscn_regexes[current_index]->sub(line, "TEMP_RENAMED_CLASS.tscn", true);
1558
line = reg_container.class_gd_regexes[current_index]->sub(line, "TEMP_RENAMED_CLASS.gd", true);
1559
line = reg_container.class_shader_regexes[current_index]->sub(line, "TEMP_RENAMED_CLASS.shader", true);
1560
}
1561
1562
// Causal renaming Spatial -> Node3D.
1563
line = reg_container.class_regexes[current_index]->sub(line, RenamesMap3To4::class_renames[current_index][1], true);
1564
1565
// Restore Spatial.tscn from TEMP_RENAMED_CLASS.tscn.
1566
if (found_ignored_items) {
1567
line = reg_container.class_temp_tscn.sub(line, reg_container.class_temp_tscn_renames[current_index], true);
1568
line = reg_container.class_temp_gd.sub(line, reg_container.class_temp_gd_renames[current_index], true);
1569
line = reg_container.class_temp_shader.sub(line, reg_container.class_temp_shader_renames[current_index], true);
1570
}
1571
}
1572
}
1573
}
1574
}
1575
}
1576
1577
Vector<String> ProjectConverter3To4::check_for_rename_classes(Vector<String> &lines, const RegExContainer &reg_container) {
1578
Vector<String> found_renames;
1579
1580
int current_line = 1;
1581
1582
for (String &line : lines) {
1583
if (uint64_t(line.length()) <= maximum_line_length) {
1584
for (unsigned int current_index = 0; RenamesMap3To4::class_renames[current_index][0]; current_index++) {
1585
if (line.contains(RenamesMap3To4::class_renames[current_index][0])) {
1586
String old_line = line;
1587
bool found_ignored_items = false;
1588
// Renaming Spatial.tscn to TEMP_RENAMED_CLASS.tscn.
1589
if (line.contains(String(RenamesMap3To4::class_renames[current_index][0]) + ".")) {
1590
found_ignored_items = true;
1591
line = reg_container.class_tscn_regexes[current_index]->sub(line, "TEMP_RENAMED_CLASS.tscn", true);
1592
line = reg_container.class_gd_regexes[current_index]->sub(line, "TEMP_RENAMED_CLASS.gd", true);
1593
line = reg_container.class_shader_regexes[current_index]->sub(line, "TEMP_RENAMED_CLASS.shader", true);
1594
}
1595
1596
// Causal renaming Spatial -> Node3D.
1597
TypedArray<RegExMatch> reg_match = reg_container.class_regexes[current_index]->search_all(line);
1598
if (reg_match.size() > 0) {
1599
found_renames.append(line_formatter(current_line, RenamesMap3To4::class_renames[current_index][0], RenamesMap3To4::class_renames[current_index][1], old_line));
1600
}
1601
1602
// Restore Spatial.tscn from TEMP_RENAMED_CLASS.tscn.
1603
if (found_ignored_items) {
1604
line = reg_container.class_temp_tscn.sub(line, reg_container.class_temp_tscn_renames[current_index], true);
1605
line = reg_container.class_temp_gd.sub(line, reg_container.class_temp_gd_renames[current_index], true);
1606
line = reg_container.class_temp_shader.sub(line, reg_container.class_temp_shader_renames[current_index], true);
1607
}
1608
}
1609
}
1610
}
1611
current_line++;
1612
}
1613
return found_renames;
1614
}
1615
1616
void ProjectConverter3To4::rename_gdscript_functions(Vector<SourceLine> &source_lines, const RegExContainer &reg_container, bool builtin) {
1617
for (SourceLine &source_line : source_lines) {
1618
if (source_line.is_comment) {
1619
continue;
1620
}
1621
1622
String &line = source_line.line;
1623
if (uint64_t(line.length()) <= maximum_line_length) {
1624
process_gdscript_line(line, reg_container, builtin);
1625
}
1626
}
1627
}
1628
1629
Vector<String> ProjectConverter3To4::check_for_rename_gdscript_functions(Vector<String> &lines, const RegExContainer &reg_container, bool builtin) {
1630
int current_line = 1;
1631
1632
Vector<String> found_renames;
1633
1634
for (String &line : lines) {
1635
if (uint64_t(line.length()) <= maximum_line_length) {
1636
String old_line = line;
1637
process_gdscript_line(line, reg_container, builtin);
1638
if (old_line != line) {
1639
found_renames.append(simple_line_formatter(current_line, old_line, line));
1640
}
1641
}
1642
}
1643
1644
return found_renames;
1645
}
1646
1647
bool ProjectConverter3To4::contains_function_call(const String &line, const String &function) const {
1648
// We want to convert the function only if it is completely standalone.
1649
// For example, when we search for "connect(", we don't want to accidentally convert "reconnect(".
1650
if (!line.contains(function)) {
1651
return false;
1652
}
1653
1654
int index = line.find(function);
1655
if (index == 0) {
1656
return true;
1657
}
1658
1659
char32_t previous_char = line.get(index - 1);
1660
return (previous_char < '0' || previous_char > '9') && (previous_char < 'a' || previous_char > 'z') && (previous_char < 'A' || previous_char > 'Z') && previous_char != '_' && previous_char != '$' && previous_char != '@';
1661
}
1662
1663
// TODO, this function should run only on all ".gd" files and also on lines in ".tscn" files which are parts of built-in Scripts.
1664
void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContainer &reg_container, bool builtin) {
1665
// In this and other functions, reg.sub() is used only after checking lines with str.contains().
1666
// With longer lines, doing so can sometimes be significantly faster.
1667
1668
if ((line.contains(".lock") || line.contains(".unlock")) && !line.contains("mtx") && !line.contains("mutex") && !line.contains("Mutex")) {
1669
line = reg_container.reg_image_lock.sub(line, "false # $1.lock() # TODOConverter3To4, Image no longer requires locking, `false` helps to not break one line if/else, so it can freely be removed", true);
1670
line = reg_container.reg_image_unlock.sub(line, "false # $1.unlock() # TODOConverter3To4, Image no longer requires locking, `false` helps to not break one line if/else, so it can freely be removed", true);
1671
}
1672
1673
// PackedStringArray(req_godot).join('.') -> '.'.join(PackedStringArray(req_godot)) PoolStringArray
1674
if (line.contains(".join")) {
1675
line = reg_container.reg_join.sub(line, "$2.join($1)", true);
1676
}
1677
1678
// -- empty() -> is_empty() Pool*Array
1679
if (line.contains("empty")) {
1680
line = reg_container.reg_is_empty.sub(line, "is_empty(", true);
1681
}
1682
1683
// -- \t.func() -> \tsuper.func() Object
1684
if (line.contains_char('(') && line.contains_char('.')) {
1685
line = reg_container.reg_super.sub(line, "$1super.$2", true); // TODO, not sure if possible, but for now this broke String text e.g. "Chosen .gitignore" -> "Chosen super.gitignore"
1686
}
1687
1688
// -- JSON.parse(a) -> JSON.new().parse(a) etc. JSON
1689
if (line.contains("parse")) {
1690
line = reg_container.reg_json_non_new.sub(line, "$1var test_json_conv = JSON.new()\n$1test_json_conv.parse($3\n$1$2test_json_conv.get_data()", true);
1691
}
1692
1693
// -- to_json(a) -> JSON.new().stringify(a) Object
1694
if (line.contains("to_json")) {
1695
line = reg_container.reg_json_to.sub(line, "JSON.new().stringify", true);
1696
}
1697
// -- parse_json(a) -> JSON.get_data() etc. Object
1698
if (line.contains("parse_json")) {
1699
line = reg_container.reg_json_parse.sub(line, "$1var test_json_conv = JSON.new()\n$1test_json_conv.parse($3\n$1$2test_json_conv.get_data()", true);
1700
}
1701
// -- JSON.print( -> JSON.stringify(
1702
if (line.contains("JSON.print(")) {
1703
line = reg_container.reg_json_print.sub(line, "JSON.stringify(", true);
1704
}
1705
1706
// -- get_node(@ -> get_node( Node
1707
if (line.contains("get_node")) {
1708
line = line.replace("get_node(@", "get_node(");
1709
}
1710
1711
if (line.contains("export")) {
1712
// 1. export(float) var lifetime: float = 3.0 -> export var lifetime: float = 3.0
1713
line = reg_container.reg_export_typed.sub(line, "export var $2: $1");
1714
// 2. export(float) var lifetime := 3.0 -> export var lifetime := 3.0
1715
line = reg_container.reg_export_inferred_type.sub(line, "export var $1 :=");
1716
// 3. export(float) var lifetime = 3.0 -> export var lifetime: float = 3.0 GDScript
1717
line = reg_container.reg_export_simple.sub(line, "export var $2: $1");
1718
// 4. export(String, 'AnonymousPro', 'CourierPrime') var _font_name = 'AnonymousPro' -> export var _font_name = 'AnonymousPro' #(String, 'AnonymousPro', 'CourierPrime') GDScript
1719
line = reg_container.reg_export_advanced.sub(line, "export var $2$3 # ($1)");
1720
}
1721
1722
// Setget Setget
1723
if (line.contains("setget")) {
1724
line = reg_container.reg_setget_setget.sub(line, "var $1$2: get = $4, set = $3", true);
1725
}
1726
1727
// Setget set
1728
if (line.contains("setget")) {
1729
line = reg_container.reg_setget_set.sub(line, "var $1$2: set = $3", true);
1730
}
1731
1732
// Setget get
1733
if (line.contains("setget")) {
1734
line = reg_container.reg_setget_get.sub(line, "var $1$2: get = $3", true);
1735
}
1736
1737
if (line.contains("window_resizable")) {
1738
// OS.set_window_resizable(a) -> get_window().unresizable = not (a)
1739
line = reg_container.reg_os_set_window_resizable.sub(line, "get_window().unresizable = not ($1)", true);
1740
// OS.window_resizable = a -> same
1741
line = reg_container.reg_os_assign_window_resizable.sub(line, "get_window().unresizable = not ($1)", true);
1742
// OS.[is_]window_resizable() -> (not get_window().unresizable)
1743
line = reg_container.reg_os_is_window_resizable.sub(line, "(not get_window().unresizable)", true);
1744
}
1745
1746
if (line.contains("window_fullscreen")) {
1747
// OS.window_fullscreen(a) -> get_window().mode = Window.MODE_EXCLUSIVE_FULLSCREEN if (a) else Window.MODE_WINDOWED
1748
line = reg_container.reg_os_set_fullscreen.sub(line, "get_window().mode = Window.MODE_EXCLUSIVE_FULLSCREEN if ($1) else Window.MODE_WINDOWED", true);
1749
// window_fullscreen = a -> same
1750
line = reg_container.reg_os_assign_fullscreen.sub(line, "get_window().mode = Window.MODE_EXCLUSIVE_FULLSCREEN if ($1) else Window.MODE_WINDOWED", true);
1751
// OS.[is_]window_fullscreen() -> ((get_window().mode == Window.MODE_EXCLUSIVE_FULLSCREEN) or (get_window().mode == Window.MODE_FULLSCREEN))
1752
line = reg_container.reg_os_is_fullscreen.sub(line, "((get_window().mode == Window.MODE_EXCLUSIVE_FULLSCREEN) or (get_window().mode == Window.MODE_FULLSCREEN))", true);
1753
}
1754
1755
if (line.contains("window_maximized")) {
1756
// OS.window_maximized(a) -> get_window().mode = Window.MODE_MAXIMIZED if (a) else Window.MODE_WINDOWED
1757
line = reg_container.reg_os_set_maximized.sub(line, "get_window().mode = Window.MODE_MAXIMIZED if ($1) else Window.MODE_WINDOWED", true);
1758
// window_maximized = a -> same
1759
line = reg_container.reg_os_assign_maximized.sub(line, "get_window().mode = Window.MODE_MAXIMIZED if ($1) else Window.MODE_WINDOWED", true);
1760
// OS.[is_]window_maximized() -> (get_window().mode == Window.MODE_MAXIMIZED)
1761
line = reg_container.reg_os_is_maximized.sub(line, "(get_window().mode == Window.MODE_MAXIMIZED)", true);
1762
}
1763
1764
if (line.contains("window_minimized")) {
1765
// OS.window_minimized(a) -> get_window().mode = Window.MODE_MINIMIZED if (a) else Window.MODE_WINDOWED
1766
line = reg_container.reg_os_set_minimized.sub(line, "get_window().mode = Window.MODE_MINIMIZED if ($1) else Window.MODE_WINDOWED", true);
1767
// window_minimized = a -> same
1768
line = reg_container.reg_os_assign_minimized.sub(line, "get_window().mode = Window.MODE_MINIMIZED if ($1) else Window.MODE_WINDOWED", true);
1769
// OS.[is_]window_minimized() -> (get_window().mode == Window.MODE_MINIMIZED)
1770
line = reg_container.reg_os_is_minimized.sub(line, "(get_window().mode == Window.MODE_MINIMIZED)", true);
1771
}
1772
1773
if (line.contains("set_use_vsync")) {
1774
// OS.set_use_vsync(a) -> get_window().window_set_vsync_mode(DisplayServer.VSYNC_ENABLED if (a) else DisplayServer.VSYNC_DISABLED)
1775
line = reg_container.reg_os_set_vsync.sub(line, "DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_ENABLED if ($1) else DisplayServer.VSYNC_DISABLED)", true);
1776
}
1777
if (line.contains("vsync_enabled")) {
1778
// vsync_enabled = a -> get_window().window_set_vsync_mode(DisplayServer.VSYNC_ENABLED if (a) else DisplayServer.VSYNC_DISABLED)
1779
line = reg_container.reg_os_assign_vsync.sub(line, "DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_ENABLED if ($1) else DisplayServer.VSYNC_DISABLED)", true);
1780
// OS.[is_]vsync_enabled() -> (DisplayServer.window_get_vsync_mode() != DisplayServer.VSYNC_DISABLED)
1781
line = reg_container.reg_os_is_vsync.sub(line, "(DisplayServer.window_get_vsync_mode() != DisplayServer.VSYNC_DISABLED)", true);
1782
}
1783
1784
if (line.contains("OS.screen_orientation")) { // keep "OS." at start
1785
// OS.screen_orientation = a -> DisplayServer.screen_set_orientation(a)
1786
line = reg_container.reg_os_assign_screen_orient.sub(line, "$1DisplayServer.screen_set_orientation($2)", true); // assignment
1787
line = line.replace("OS.screen_orientation", "DisplayServer.screen_get_orientation()"); // value access
1788
}
1789
1790
if (line.contains("_window_always_on_top")) {
1791
// OS.set_window_always_on_top(a) -> get_window().always_on_top = (a)
1792
line = reg_container.reg_os_set_always_on_top.sub(line, "get_window().always_on_top = ($1)", true);
1793
// OS.is_window_always_on_top() -> get_window().always_on_top
1794
line = reg_container.reg_os_is_always_on_top.sub(line, "get_window().always_on_top", true);
1795
}
1796
1797
if (line.contains("et_borderless_window")) {
1798
// OS.set_borderless_window(a) -> get_window().borderless = (a)
1799
line = reg_container.reg_os_set_borderless.sub(line, "get_window().borderless = ($1)", true);
1800
// OS.get_borderless_window() -> get_window().borderless
1801
line = reg_container.reg_os_get_borderless.sub(line, "get_window().borderless", true);
1802
}
1803
1804
// OS.SCREEN_ORIENTATION_* -> DisplayServer.SCREEN_*
1805
if (line.contains("OS.SCREEN_ORIENTATION_")) {
1806
line = reg_container.reg_os_screen_orient_enum.sub(line, "DisplayServer.SCREEN_$1", true);
1807
}
1808
1809
// OS -> Window simple replacements with optional set/get.
1810
if (line.contains("current_screen")) {
1811
line = reg_container.reg_os_current_screen.sub(line, "get_window().$1current_screen", true);
1812
}
1813
if (line.contains("min_window_size")) {
1814
line = reg_container.reg_os_min_window_size.sub(line, "get_window().$1min_size", true);
1815
}
1816
if (line.contains("max_window_size")) {
1817
line = reg_container.reg_os_max_window_size.sub(line, "get_window().$1max_size", true);
1818
}
1819
if (line.contains("window_position")) {
1820
line = reg_container.reg_os_window_position.sub(line, "get_window().$1position", true);
1821
}
1822
if (line.contains("window_size")) {
1823
line = reg_container.reg_os_window_size.sub(line, "get_window().$1size", true);
1824
}
1825
if (line.contains("et_screen_orientation")) {
1826
line = reg_container.reg_os_getset_screen_orient.sub(line, "DisplayServer.screen_$1et_orientation", true);
1827
}
1828
1829
// Instantiate
1830
if (contains_function_call(line, "instance")) {
1831
line = reg_container.reg_instantiate.sub(line, ".instantiate($1)", true);
1832
}
1833
1834
// -- r.move_and_slide( a, b, c, d, e ) -> r.set_velocity(a) ... r.move_and_slide() KinematicBody
1835
if (contains_function_call(line, "move_and_slide(")) {
1836
int start = line.find("move_and_slide(");
1837
int end = get_end_parenthesis(line.substr(start)) + 1;
1838
if (end > -1) {
1839
String base_obj = get_object_of_execution(line.substr(0, start));
1840
String starting_space = get_starting_space(line);
1841
1842
Vector<String> parts = parse_arguments(line.substr(start, end));
1843
if (parts.size() >= 1) {
1844
String line_new;
1845
1846
// motion_velocity
1847
line_new += starting_space + base_obj + "set_velocity(" + parts[0] + ")\n";
1848
1849
// up_direction
1850
if (parts.size() >= 2) {
1851
line_new += starting_space + base_obj + "set_up_direction(" + parts[1] + ")\n";
1852
}
1853
1854
// stop_on_slope
1855
if (parts.size() >= 3) {
1856
line_new += starting_space + base_obj + "set_floor_stop_on_slope_enabled(" + parts[2] + ")\n";
1857
}
1858
1859
// max_slides
1860
if (parts.size() >= 4) {
1861
line_new += starting_space + base_obj + "set_max_slides(" + parts[3] + ")\n";
1862
}
1863
1864
// floor_max_angle
1865
if (parts.size() >= 5) {
1866
line_new += starting_space + base_obj + "set_floor_max_angle(" + parts[4] + ")\n";
1867
}
1868
1869
// infiinite_interia
1870
if (parts.size() >= 6) {
1871
line_new += starting_space + "# TODOConverter3To4 infinite_inertia were removed in Godot 4 - previous value `" + parts[5] + "`\n";
1872
}
1873
1874
line_new += starting_space + base_obj + "move_and_slide()";
1875
1876
if (!line.begins_with(starting_space + "move_and_slide")) {
1877
line = line_new + "\n" + line.substr(0, start) + "velocity" + line.substr(end + start);
1878
} else {
1879
line = line_new + line.substr(end + start);
1880
}
1881
}
1882
}
1883
}
1884
1885
// -- r.move_and_slide_with_snap( a, b, c, d, e ) -> r.set_velocity(a) ... r.move_and_slide() KinematicBody
1886
if (contains_function_call(line, "move_and_slide_with_snap(")) {
1887
int start = line.find("move_and_slide_with_snap(");
1888
int end = get_end_parenthesis(line.substr(start)) + 1;
1889
if (end > -1) {
1890
String base_obj = get_object_of_execution(line.substr(0, start));
1891
String starting_space = get_starting_space(line);
1892
1893
Vector<String> parts = parse_arguments(line.substr(start, end));
1894
if (parts.size() >= 1) {
1895
String line_new;
1896
1897
// motion_velocity
1898
line_new += starting_space + base_obj + "set_velocity(" + parts[0] + ")\n";
1899
1900
// snap
1901
if (parts.size() >= 2) {
1902
line_new += starting_space + "# TODOConverter3To4 looks that snap in Godot 4 is float, not vector like in Godot 3 - previous value `" + parts[1] + "`\n";
1903
}
1904
1905
// up_direction
1906
if (parts.size() >= 3) {
1907
line_new += starting_space + base_obj + "set_up_direction(" + parts[2] + ")\n";
1908
}
1909
1910
// stop_on_slope
1911
if (parts.size() >= 4) {
1912
line_new += starting_space + base_obj + "set_floor_stop_on_slope_enabled(" + parts[3] + ")\n";
1913
}
1914
1915
// max_slides
1916
if (parts.size() >= 5) {
1917
line_new += starting_space + base_obj + "set_max_slides(" + parts[4] + ")\n";
1918
}
1919
1920
// floor_max_angle
1921
if (parts.size() >= 6) {
1922
line_new += starting_space + base_obj + "set_floor_max_angle(" + parts[5] + ")\n";
1923
}
1924
1925
// infiinite_interia
1926
if (parts.size() >= 7) {
1927
line_new += starting_space + "# TODOConverter3To4 infinite_inertia were removed in Godot 4 - previous value `" + parts[6] + "`\n";
1928
}
1929
1930
line_new += starting_space + base_obj + "move_and_slide()";
1931
1932
if (!line.begins_with(starting_space + "move_and_slide_with_snap")) {
1933
line = line_new + "\n" + line.substr(0, start) + "velocity" + line.substr(end + start);
1934
} else {
1935
line = line_new + line.substr(end + start);
1936
}
1937
}
1938
}
1939
}
1940
1941
// -- sort_custom( a , b ) -> sort_custom(Callable( a , b )) Object
1942
if (contains_function_call(line, "sort_custom(")) {
1943
int start = line.find("sort_custom(");
1944
int end = get_end_parenthesis(line.substr(start)) + 1;
1945
if (end > -1) {
1946
Vector<String> parts = parse_arguments(line.substr(start, end));
1947
if (parts.size() == 2) {
1948
line = line.substr(0, start) + "sort_custom(Callable(" + parts[0] + ", " + parts[1] + "))" + line.substr(end + start);
1949
}
1950
}
1951
}
1952
1953
// -- list_dir_begin( ) -> list_dir_begin() Object
1954
if (contains_function_call(line, "list_dir_begin(")) {
1955
int start = line.find("list_dir_begin(");
1956
int end = get_end_parenthesis(line.substr(start)) + 1;
1957
if (end > -1) {
1958
line = line.substr(0, start) + "list_dir_begin() " + line.substr(end + start) + "# TODOConverter3To4 fill missing arguments https://github.com/godotengine/godot/pull/40547";
1959
}
1960
}
1961
1962
// -- draw_line(1,2,3,4,5) -> draw_line(1, 2, 3, 4) CanvasItem
1963
if (contains_function_call(line, "draw_line(")) {
1964
int start = line.find("draw_line(");
1965
int end = get_end_parenthesis(line.substr(start)) + 1;
1966
if (end > -1) {
1967
Vector<String> parts = parse_arguments(line.substr(start, end));
1968
if (parts.size() == 5) {
1969
line = line.substr(0, start) + "draw_line(" + parts[0] + ", " + parts[1] + ", " + parts[2] + ", " + parts[3] + ")" + line.substr(end + start);
1970
}
1971
}
1972
}
1973
1974
// -- func c(var a, var b) -> func c(a, b)
1975
if (line.contains("func ") && line.contains("var ")) {
1976
int start = line.find("func ");
1977
start = line.substr(start).find_char('(') + start;
1978
int end = get_end_parenthesis(line.substr(start)) + 1;
1979
if (end > -1) {
1980
Vector<String> parts = parse_arguments(line.substr(start, end));
1981
1982
String start_string = line.substr(0, start) + "(";
1983
for (int i = 0; i < parts.size(); i++) {
1984
start_string += parts[i].strip_edges().trim_prefix("var ");
1985
if (i != parts.size() - 1) {
1986
start_string += ", ";
1987
}
1988
}
1989
line = start_string + ")" + line.substr(end + start);
1990
}
1991
}
1992
1993
// -- yield(this, \"timeout\") -> await this.timeout GDScript
1994
if (contains_function_call(line, "yield(")) {
1995
int start = line.find("yield(");
1996
int end = get_end_parenthesis(line.substr(start)) + 1;
1997
if (end > -1) {
1998
Vector<String> parts = parse_arguments(line.substr(start, end));
1999
if (parts.size() == 2) {
2000
if (builtin) {
2001
line = line.substr(0, start) + "await " + parts[0] + "." + parts[1].replace("\\\"", "").replace("\\'", "").remove_char(' ') + line.substr(end + start);
2002
} else {
2003
line = line.substr(0, start) + "await " + parts[0] + "." + parts[1].remove_chars("\"' ") + line.substr(end + start);
2004
}
2005
}
2006
}
2007
}
2008
2009
// -- parse_json( AA ) -> TODO Object
2010
if (contains_function_call(line, "parse_json(")) {
2011
int start = line.find("parse_json(");
2012
int end = get_end_parenthesis(line.substr(start)) + 1;
2013
if (end > -1) {
2014
Vector<String> parts = parse_arguments(line.substr(start, end));
2015
line = line.substr(0, start) + "JSON.new().stringify(" + connect_arguments(parts, 0) + ")" + line.substr(end + start);
2016
}
2017
}
2018
2019
// -- .xform(Vector3(a,b,c)) -> * Vector3(a,b,c) Transform
2020
if (line.contains(".xform(")) {
2021
int start = line.find(".xform(");
2022
int end = get_end_parenthesis(line.substr(start)) + 1;
2023
if (end > -1) {
2024
Vector<String> parts = parse_arguments(line.substr(start, end));
2025
if (parts.size() == 1) {
2026
line = line.substr(0, start) + " * (" + parts[0] + ")" + line.substr(end + start);
2027
}
2028
}
2029
}
2030
2031
// -- .xform_inv(Vector3(a,b,c)) -> * Vector3(a,b,c) Transform
2032
if (line.contains(".xform_inv(")) {
2033
int start = line.find(".xform_inv(");
2034
int end = get_end_parenthesis(line.substr(start)) + 1;
2035
if (end > -1) {
2036
String object_exec = get_object_of_execution(line.substr(0, start));
2037
if (line.contains(object_exec + ".xform")) {
2038
int start2 = line.find(object_exec + ".xform");
2039
Vector<String> parts = parse_arguments(line.substr(start, end));
2040
if (parts.size() == 1) {
2041
line = line.substr(0, start2) + "(" + parts[0] + ") * " + object_exec + line.substr(end + start);
2042
}
2043
}
2044
}
2045
}
2046
2047
// -- "(connect(A,B,C,D,E) != OK):", "(connect(A, Callable(B, C).bind(D), E) Object
2048
if (contains_function_call(line, "connect(")) {
2049
int start = line.find("connect(");
2050
int end = get_end_parenthesis(line.substr(start)) + 1;
2051
if (end > -1) {
2052
Vector<String> parts = parse_arguments(line.substr(start, end));
2053
if (parts.size() == 3) {
2054
line = line.substr(0, start) + "connect(" + parts[0] + ", Callable(" + parts[1] + ", " + parts[2] + "))" + line.substr(end + start);
2055
} else if (parts.size() >= 4) {
2056
line = line.substr(0, start) + "connect(" + parts[0] + ", Callable(" + parts[1] + ", " + parts[2] + ").bind(" + parts[3].lstrip(" [").rstrip("] ") + ")" + connect_arguments(parts, 4) + ")" + line.substr(end + start);
2057
}
2058
}
2059
}
2060
// -- disconnect(a,b,c) -> disconnect(a,Callable(b,c)) Object
2061
if (contains_function_call(line, "disconnect(")) {
2062
int start = line.find("disconnect(");
2063
int end = get_end_parenthesis(line.substr(start)) + 1;
2064
if (end > -1) {
2065
Vector<String> parts = parse_arguments(line.substr(start, end));
2066
if (parts.size() == 3) {
2067
line = line.substr(0, start) + "disconnect(" + parts[0] + ", Callable(" + parts[1] + ", " + parts[2] + "))" + line.substr(end + start);
2068
}
2069
}
2070
}
2071
// -- is_connected(a,b,c) -> is_connected(a,Callable(b,c)) Object
2072
if (contains_function_call(line, "is_connected(")) {
2073
int start = line.find("is_connected(");
2074
int end = get_end_parenthesis(line.substr(start)) + 1;
2075
if (end > -1) {
2076
Vector<String> parts = parse_arguments(line.substr(start, end));
2077
if (parts.size() == 3) {
2078
line = line.substr(0, start) + "is_connected(" + parts[0] + ", Callable(" + parts[1] + ", " + parts[2] + "))" + line.substr(end + start);
2079
}
2080
}
2081
}
2082
// -- "(tween_method(A,B,C,D,E) != OK):", "(tween_method(Callable(A,B),C,D,E) Object
2083
// -- "(tween_method(A,B,C,D,E,[F,G]) != OK):", "(tween_method(Callable(A,B).bind(F,G),C,D,E) Object
2084
if (contains_function_call(line, "tween_method(")) {
2085
int start = line.find("tween_method(");
2086
int end = get_end_parenthesis(line.substr(start)) + 1;
2087
if (end > -1) {
2088
Vector<String> parts = parse_arguments(line.substr(start, end));
2089
if (parts.size() == 5) {
2090
line = line.substr(0, start) + "tween_method(Callable(" + parts[0] + ", " + parts[1] + "), " + parts[2] + ", " + parts[3] + ", " + parts[4] + ")" + line.substr(end + start);
2091
} else if (parts.size() >= 6) {
2092
line = line.substr(0, start) + "tween_method(Callable(" + parts[0] + ", " + parts[1] + ").bind(" + connect_arguments(parts, 5).substr(1).lstrip(" [").rstrip("] ") + "), " + parts[2] + ", " + parts[3] + ", " + parts[4] + ")" + line.substr(end + start);
2093
}
2094
}
2095
}
2096
// -- "(tween_callback(A,B,[C,D]) != OK):", "(connect(Callable(A,B).bind(C,D)) Object
2097
if (contains_function_call(line, "tween_callback(")) {
2098
int start = line.find("tween_callback(");
2099
int end = get_end_parenthesis(line.substr(start)) + 1;
2100
if (end > -1) {
2101
Vector<String> parts = parse_arguments(line.substr(start, end));
2102
if (parts.size() == 2) {
2103
line = line.substr(0, start) + "tween_callback(Callable(" + parts[0] + ", " + parts[1] + "))" + line.substr(end + start);
2104
} else if (parts.size() >= 3) {
2105
line = line.substr(0, start) + "tween_callback(Callable(" + parts[0] + ", " + parts[1] + ").bind(" + connect_arguments(parts, 2).substr(1).lstrip(" [").rstrip("] ") + "))" + line.substr(end + start);
2106
}
2107
}
2108
}
2109
// -- start(a,b) -> start(Callable(a, b)) Thread
2110
// -- start(a,b,c,d) -> start(Callable(a, b).bind(c), d) Thread
2111
if (contains_function_call(line, "start(")) {
2112
int start = line.find("start(");
2113
int end = get_end_parenthesis(line.substr(start)) + 1;
2114
// Protection from 'func start'
2115
if (!line.begins_with("func ")) {
2116
if (end > -1) {
2117
Vector<String> parts = parse_arguments(line.substr(start, end));
2118
if (parts.size() == 2) {
2119
line = line.substr(0, start) + "start(Callable(" + parts[0] + ", " + parts[1] + "))" + line.substr(end + start);
2120
} else if (parts.size() >= 3) {
2121
line = line.substr(0, start) + "start(Callable(" + parts[0] + ", " + parts[1] + ").bind(" + parts[2] + ")" + connect_arguments(parts, 3) + ")" + line.substr(end + start);
2122
}
2123
}
2124
}
2125
}
2126
// -- func _init(p_x:int).(p_x): -> func _init(p_x:int):\n\tsuper(p_x) Object # https://github.com/godotengine/godot/issues/70542
2127
if (line.contains(" _init(") && line.rfind_char(':') > 0) {
2128
// func _init(p_arg1).(super4, super5, super6)->void:
2129
// ^--^indent ^super_start super_end^
2130
int indent = line.count("\t", 0, line.find("func"));
2131
int super_start = line.find(".(");
2132
int super_end = line.rfind_char(')');
2133
if (super_start > 0 && super_end > super_start) {
2134
line = line.substr(0, super_start) + line.substr(super_end + 1) + "\n" + String("\t").repeat(indent + 1) + "super" + line.substr(super_start + 1, super_end - super_start);
2135
}
2136
}
2137
2138
// create_from_image(aa, bb) -> create_from_image(aa) #, bb ImageTexture
2139
if (contains_function_call(line, "create_from_image(")) {
2140
int start = line.find("create_from_image(");
2141
int end = get_end_parenthesis(line.substr(start)) + 1;
2142
if (end > -1) {
2143
Vector<String> parts = parse_arguments(line.substr(start, end));
2144
if (parts.size() == 2) {
2145
line = line.substr(0, start) + "create_from_image(" + parts[0] + ") " + "#," + parts[1] + line.substr(end + start);
2146
}
2147
}
2148
}
2149
// set_cell_item(a, b, c, d ,e) -> set_cell_item(Vector3(a, b, c), d ,e)
2150
if (contains_function_call(line, "set_cell_item(")) {
2151
int start = line.find("set_cell_item(");
2152
int end = get_end_parenthesis(line.substr(start)) + 1;
2153
if (end > -1) {
2154
Vector<String> parts = parse_arguments(line.substr(start, end));
2155
if (parts.size() > 2) {
2156
line = line.substr(0, start) + "set_cell_item(Vector3(" + parts[0] + ", " + parts[1] + ", " + parts[2] + ")" + connect_arguments(parts, 3).lstrip(" ") + ")" + line.substr(end + start);
2157
}
2158
}
2159
}
2160
// get_cell_item(a, b, c) -> get_cell_item(Vector3i(a, b, c))
2161
if (contains_function_call(line, "get_cell_item(")) {
2162
int start = line.find("get_cell_item(");
2163
int end = get_end_parenthesis(line.substr(start)) + 1;
2164
if (end > -1) {
2165
Vector<String> parts = parse_arguments(line.substr(start, end));
2166
if (parts.size() == 3) {
2167
line = line.substr(0, start) + "get_cell_item(Vector3i(" + parts[0] + ", " + parts[1] + ", " + parts[2] + "))" + line.substr(end + start);
2168
}
2169
}
2170
}
2171
// get_cell_item_orientation(a, b, c) -> get_cell_item_orientation(Vector3i(a, b, c))
2172
if (contains_function_call(line, "get_cell_item_orientation(")) {
2173
int start = line.find("get_cell_item_orientation(");
2174
int end = get_end_parenthesis(line.substr(start)) + 1;
2175
if (end > -1) {
2176
Vector<String> parts = parse_arguments(line.substr(start, end));
2177
if (parts.size() == 3) {
2178
line = line.substr(0, start) + "get_cell_item_orientation(Vector3i(" + parts[0] + ", " + parts[1] + ", " + parts[2] + "))" + line.substr(end + start);
2179
}
2180
}
2181
}
2182
// apply_impulse(A, B) -> apply_impulse(B, A)
2183
if (contains_function_call(line, "apply_impulse(")) {
2184
int start = line.find("apply_impulse(");
2185
int end = get_end_parenthesis(line.substr(start)) + 1;
2186
if (end > -1) {
2187
Vector<String> parts = parse_arguments(line.substr(start, end));
2188
if (parts.size() == 2) {
2189
line = line.substr(0, start) + "apply_impulse(" + parts[1] + ", " + parts[0] + ")" + line.substr(end + start);
2190
}
2191
}
2192
}
2193
// apply_force(A, B) -> apply_force(B, A)
2194
if (contains_function_call(line, "apply_force(")) {
2195
int start = line.find("apply_force(");
2196
int end = get_end_parenthesis(line.substr(start)) + 1;
2197
if (end > -1) {
2198
Vector<String> parts = parse_arguments(line.substr(start, end));
2199
if (parts.size() == 2) {
2200
line = line.substr(0, start) + "apply_force(" + parts[1] + ", " + parts[0] + ")" + line.substr(end + start);
2201
}
2202
}
2203
}
2204
// map_to_world(a, b, c) -> map_to_local(Vector3i(a, b, c))
2205
if (contains_function_call(line, "map_to_world(")) {
2206
int start = line.find("map_to_world(");
2207
int end = get_end_parenthesis(line.substr(start)) + 1;
2208
if (end > -1) {
2209
Vector<String> parts = parse_arguments(line.substr(start, end));
2210
if (parts.size() == 3) {
2211
line = line.substr(0, start) + "map_to_local(Vector3i(" + parts[0] + ", " + parts[1] + ", " + parts[2] + "))" + line.substr(end + start);
2212
} else if (parts.size() == 1) {
2213
line = line.substr(0, start) + "map_to_local(" + parts[0] + ")" + line.substr(end + start);
2214
}
2215
}
2216
}
2217
2218
// set_rotating(true) -> set_ignore_rotation(false)
2219
if (contains_function_call(line, "set_rotating(")) {
2220
int start = line.find("set_rotating(");
2221
int end = get_end_parenthesis(line.substr(start)) + 1;
2222
if (end > -1) {
2223
Vector<String> parts = parse_arguments(line.substr(start, end));
2224
if (parts.size() == 1) {
2225
String opposite = parts[0] == "true" ? "false" : "true";
2226
line = line.substr(0, start) + "set_ignore_rotation(" + opposite + ")";
2227
}
2228
}
2229
}
2230
2231
// OS.get_window_safe_area() -> DisplayServer.get_display_safe_area()
2232
if (line.contains("OS.get_window_safe_area(")) {
2233
int start = line.find("OS.get_window_safe_area(");
2234
int end = get_end_parenthesis(line.substr(start)) + 1;
2235
if (end > -1) {
2236
Vector<String> parts = parse_arguments(line.substr(start, end));
2237
if (parts.is_empty()) {
2238
line = line.substr(0, start) + "DisplayServer.get_display_safe_area()" + line.substr(end + start);
2239
}
2240
}
2241
}
2242
// draw_rect(a,b,c,d,e) -> draw_rect(a,b,c,d)#e) TODOConverter3To4 Antialiasing argument is missing
2243
if (contains_function_call(line, "draw_rect(")) {
2244
int start = line.find("draw_rect(");
2245
int end = get_end_parenthesis(line.substr(start)) + 1;
2246
if (end > -1) {
2247
Vector<String> parts = parse_arguments(line.substr(start, end));
2248
if (parts.size() == 5) {
2249
line = line.substr(0, start) + "draw_rect(" + parts[0] + ", " + parts[1] + ", " + parts[2] + ", " + parts[3] + ")" + line.substr(end + start) + "# " + parts[4] + ") TODOConverter3To4 Antialiasing argument is missing";
2250
}
2251
}
2252
}
2253
// get_focus_owner() -> get_viewport().gui_get_focus_owner()
2254
if (contains_function_call(line, "get_focus_owner()")) {
2255
line = line.replace("get_focus_owner()", "get_viewport().gui_get_focus_owner()");
2256
}
2257
2258
// button.pressed = 1 -> button.button_pressed = 1
2259
if (line.contains(".pressed")) {
2260
int start = line.find(".pressed");
2261
bool foundNextEqual = false;
2262
String line_to_check = line.substr(start + String(".pressed").length());
2263
for (int current_index = 0; line_to_check.length() > current_index; current_index++) {
2264
char32_t chr = line_to_check.get(current_index);
2265
if (chr == '\t' || chr == ' ') {
2266
continue;
2267
} else if (chr == '=') {
2268
foundNextEqual = true;
2269
} else {
2270
break;
2271
}
2272
}
2273
if (foundNextEqual) {
2274
line = line.substr(0, start) + ".button_pressed" + line.substr(start + String(".pressed").length());
2275
}
2276
}
2277
2278
// rotating = true -> ignore_rotation = false # reversed "rotating" for Camera2D
2279
if (contains_function_call(line, "rotating")) {
2280
String function_name = "rotating";
2281
int start = line.find(function_name);
2282
bool foundNextEqual = false;
2283
String line_to_check = line.substr(start + function_name.length());
2284
String assigned_value;
2285
for (int current_index = 0; line_to_check.length() > current_index; current_index++) {
2286
char32_t chr = line_to_check.get(current_index);
2287
if (chr == '\t' || chr == ' ') {
2288
continue;
2289
} else if (chr == '=') {
2290
foundNextEqual = true;
2291
assigned_value = line.substr(start + function_name.length() + current_index + 1).strip_edges();
2292
assigned_value = assigned_value == "true" ? "false" : "true";
2293
} else {
2294
break;
2295
}
2296
}
2297
if (foundNextEqual) {
2298
line = line.substr(0, start) + "ignore_rotation = " + assigned_value + " # reversed \"rotating\" for Camera2D";
2299
}
2300
}
2301
2302
// OS -> Time functions
2303
if (line.contains("OS.get_ticks_msec")) {
2304
line = line.replace("OS.get_ticks_msec", "Time.get_ticks_msec");
2305
}
2306
if (line.contains("OS.get_ticks_usec")) {
2307
line = line.replace("OS.get_ticks_usec", "Time.get_ticks_usec");
2308
}
2309
if (line.contains("OS.get_unix_time")) {
2310
line = line.replace("OS.get_unix_time", "Time.get_unix_time_from_system");
2311
}
2312
if (line.contains("OS.get_datetime")) {
2313
line = line.replace("OS.get_datetime", "Time.get_datetime_dict_from_system");
2314
}
2315
2316
// OS -> DisplayServer
2317
if (line.contains("OS.get_display_cutouts")) {
2318
line = line.replace("OS.get_display_cutouts", "DisplayServer.get_display_cutouts");
2319
}
2320
if (line.contains("OS.get_screen_count")) {
2321
line = line.replace("OS.get_screen_count", "DisplayServer.get_screen_count");
2322
}
2323
if (line.contains("OS.get_screen_dpi")) {
2324
line = line.replace("OS.get_screen_dpi", "DisplayServer.screen_get_dpi");
2325
}
2326
if (line.contains("OS.get_screen_max_scale")) {
2327
line = line.replace("OS.get_screen_max_scale", "DisplayServer.screen_get_max_scale");
2328
}
2329
if (line.contains("OS.get_screen_position")) {
2330
line = line.replace("OS.get_screen_position", "DisplayServer.screen_get_position");
2331
}
2332
if (line.contains("OS.get_screen_refresh_rate")) {
2333
line = line.replace("OS.get_screen_refresh_rate", "DisplayServer.screen_get_refresh_rate");
2334
}
2335
if (line.contains("OS.get_screen_scale")) {
2336
line = line.replace("OS.get_screen_scale", "DisplayServer.screen_get_scale");
2337
}
2338
if (line.contains("OS.get_screen_size")) {
2339
line = line.replace("OS.get_screen_size", "DisplayServer.screen_get_size");
2340
}
2341
if (line.contains("OS.set_icon")) {
2342
line = line.replace("OS.set_icon", "DisplayServer.set_icon");
2343
}
2344
if (line.contains("OS.set_native_icon")) {
2345
line = line.replace("OS.set_native_icon", "DisplayServer.set_native_icon");
2346
}
2347
2348
// OS -> Window
2349
if (line.contains("OS.window_borderless")) {
2350
line = line.replace("OS.window_borderless", "get_window().borderless");
2351
}
2352
if (line.contains("OS.get_real_window_size")) {
2353
line = line.replace("OS.get_real_window_size", "get_window().get_size_with_decorations");
2354
}
2355
if (line.contains("OS.is_window_focused")) {
2356
line = line.replace("OS.is_window_focused", "get_window().has_focus");
2357
}
2358
if (line.contains("OS.move_window_to_foreground")) {
2359
line = line.replace("OS.move_window_to_foreground", "get_window().grab_focus");
2360
}
2361
if (line.contains("OS.request_attention")) {
2362
line = line.replace("OS.request_attention", "get_window().request_attention");
2363
}
2364
if (line.contains("OS.set_window_title")) {
2365
line = line.replace("OS.set_window_title", "get_window().set_title");
2366
}
2367
2368
// get_tree().set_input_as_handled() -> get_viewport().set_input_as_handled()
2369
if (line.contains("get_tree().set_input_as_handled()")) {
2370
line = line.replace("get_tree().set_input_as_handled()", "get_viewport().set_input_as_handled()");
2371
}
2372
2373
// Fix the simple case of using _unhandled_key_input
2374
// func _unhandled_key_input(event: InputEventKey) -> _unhandled_key_input(event: InputEvent)
2375
if (line.contains("_unhandled_key_input(event: InputEventKey)")) {
2376
line = line.replace("_unhandled_key_input(event: InputEventKey)", "_unhandled_key_input(event: InputEvent)");
2377
}
2378
2379
if (line.contains("Engine.editor_hint")) {
2380
line = line.replace("Engine.editor_hint", "Engine.is_editor_hint()");
2381
}
2382
}
2383
2384
void ProjectConverter3To4::process_csharp_line(String &line, const RegExContainer &reg_container) {
2385
line = line.replace("OS.GetWindowSafeArea()", "DisplayServer.ScreenGetUsableRect()");
2386
2387
// GetTree().SetInputAsHandled() -> GetViewport().SetInputAsHandled()
2388
if (line.contains("GetTree().SetInputAsHandled()")) {
2389
line = line.replace("GetTree().SetInputAsHandled()", "GetViewport().SetInputAsHandled()");
2390
}
2391
2392
// Fix the simple case of using _UnhandledKeyInput
2393
// func _UnhandledKeyInput(InputEventKey @event) -> _UnhandledKeyInput(InputEvent @event)
2394
if (line.contains("_UnhandledKeyInput(InputEventKey @event)")) {
2395
line = line.replace("_UnhandledKeyInput(InputEventKey @event)", "_UnhandledKeyInput(InputEvent @event)");
2396
}
2397
2398
// -- Connect(,,,things) -> Connect(,Callable(,),things) Object
2399
if (line.contains("Connect(")) {
2400
int start = line.find("Connect(");
2401
// Protection from disconnect
2402
if (start == 0 || line.get(start - 1) != 's') {
2403
int end = get_end_parenthesis(line.substr(start)) + 1;
2404
if (end > -1) {
2405
Vector<String> parts = parse_arguments(line.substr(start, end));
2406
if (parts.size() >= 3) {
2407
line = line.substr(0, start) + "Connect(" + parts[0] + ", new Callable(" + parts[1] + ", " + parts[2] + ")" + connect_arguments(parts, 3) + ")" + line.substr(end + start);
2408
}
2409
}
2410
}
2411
}
2412
// -- Disconnect(a,b,c) -> Disconnect(a,Callable(b,c)) Object
2413
if (line.contains("Disconnect(")) {
2414
int start = line.find("Disconnect(");
2415
int end = get_end_parenthesis(line.substr(start)) + 1;
2416
if (end > -1) {
2417
Vector<String> parts = parse_arguments(line.substr(start, end));
2418
if (parts.size() == 3) {
2419
line = line.substr(0, start) + "Disconnect(" + parts[0] + ", new Callable(" + parts[1] + ", " + parts[2] + "))" + line.substr(end + start);
2420
}
2421
}
2422
}
2423
// -- IsConnected(a,b,c) -> IsConnected(a,Callable(b,c)) Object
2424
if (line.contains("IsConnected(")) {
2425
int start = line.find("IsConnected(");
2426
int end = get_end_parenthesis(line.substr(start)) + 1;
2427
if (end > -1) {
2428
Vector<String> parts = parse_arguments(line.substr(start, end));
2429
if (parts.size() == 3) {
2430
line = line.substr(0, start) + "IsConnected(" + parts[0] + ", new Callable(" + parts[1] + ", " + parts[2] + "))" + line.substr(end + start);
2431
}
2432
}
2433
}
2434
}
2435
2436
void ProjectConverter3To4::rename_csharp_functions(Vector<SourceLine> &source_lines, const RegExContainer &reg_container) {
2437
for (SourceLine &source_line : source_lines) {
2438
if (source_line.is_comment) {
2439
continue;
2440
}
2441
2442
String &line = source_line.line;
2443
if (uint64_t(line.length()) <= maximum_line_length) {
2444
process_csharp_line(line, reg_container);
2445
}
2446
}
2447
}
2448
2449
Vector<String> ProjectConverter3To4::check_for_rename_csharp_functions(Vector<String> &lines, const RegExContainer &reg_container) {
2450
int current_line = 1;
2451
2452
Vector<String> found_renames;
2453
2454
for (String &line : lines) {
2455
if (uint64_t(line.length()) <= maximum_line_length) {
2456
String old_line = line;
2457
process_csharp_line(line, reg_container);
2458
if (old_line != line) {
2459
found_renames.append(simple_line_formatter(current_line, old_line, line));
2460
}
2461
}
2462
}
2463
2464
return found_renames;
2465
}
2466
2467
void ProjectConverter3To4::rename_csharp_attributes(Vector<SourceLine> &source_lines, const RegExContainer &reg_container) {
2468
static String error_message = "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using Multiplayer.GetRemoteSenderId()\n";
2469
2470
for (SourceLine &source_line : source_lines) {
2471
if (source_line.is_comment) {
2472
continue;
2473
}
2474
2475
String &line = source_line.line;
2476
if (uint64_t(line.length()) <= maximum_line_length) {
2477
line = reg_container.keyword_csharp_remote.sub(line, "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", true);
2478
line = reg_container.keyword_csharp_remotesync.sub(line, "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", true);
2479
line = reg_container.keyword_csharp_puppet.sub(line, "[RPC]", true);
2480
line = reg_container.keyword_csharp_puppetsync.sub(line, "[RPC(CallLocal = true)]", true);
2481
line = reg_container.keyword_csharp_master.sub(line, error_message + "[RPC]", true);
2482
line = reg_container.keyword_csharp_mastersync.sub(line, error_message + "[RPC(CallLocal = true)]", true);
2483
}
2484
}
2485
}
2486
2487
Vector<String> ProjectConverter3To4::check_for_rename_csharp_attributes(Vector<String> &lines, const RegExContainer &reg_container) {
2488
int current_line = 1;
2489
2490
Vector<String> found_renames;
2491
2492
for (String &line : lines) {
2493
if (uint64_t(line.length()) <= maximum_line_length) {
2494
String old;
2495
old = line;
2496
line = reg_container.keyword_csharp_remote.sub(line, "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", true);
2497
if (old != line) {
2498
found_renames.append(line_formatter(current_line, "[Remote]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", line));
2499
}
2500
2501
old = line;
2502
line = reg_container.keyword_csharp_remotesync.sub(line, "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", true);
2503
if (old != line) {
2504
found_renames.append(line_formatter(current_line, "[RemoteSync]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", line));
2505
}
2506
2507
old = line;
2508
line = reg_container.keyword_csharp_puppet.sub(line, "[RPC]", true);
2509
if (old != line) {
2510
found_renames.append(line_formatter(current_line, "[Puppet]", "[RPC]", line));
2511
}
2512
2513
old = line;
2514
line = reg_container.keyword_csharp_puppetsync.sub(line, "[RPC(CallLocal = true)]", true);
2515
if (old != line) {
2516
found_renames.append(line_formatter(current_line, "[PuppetSync]", "[RPC(CallLocal = true)]", line));
2517
}
2518
2519
old = line;
2520
line = reg_container.keyword_csharp_master.sub(line, "[RPC]", true);
2521
if (old != line) {
2522
found_renames.append(line_formatter(current_line, "[Master]", "[RPC]", line));
2523
}
2524
2525
old = line;
2526
line = reg_container.keyword_csharp_mastersync.sub(line, "[RPC(CallLocal = true)]", true);
2527
if (old != line) {
2528
found_renames.append(line_formatter(current_line, "[MasterSync]", "[RPC(CallLocal = true)]", line));
2529
}
2530
}
2531
current_line++;
2532
}
2533
2534
return found_renames;
2535
}
2536
2537
_FORCE_INLINE_ static String builtin_escape(const String &p_str, bool p_builtin) {
2538
if (p_builtin) {
2539
return p_str.replace("\"", "\\\"");
2540
} else {
2541
return p_str;
2542
}
2543
}
2544
2545
void ProjectConverter3To4::rename_gdscript_keywords(Vector<SourceLine> &source_lines, const RegExContainer &reg_container, bool builtin) {
2546
static String error_message = "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using get_multiplayer().get_remote_sender_id()\n";
2547
2548
for (SourceLine &source_line : source_lines) {
2549
if (source_line.is_comment) {
2550
continue;
2551
}
2552
2553
String &line = source_line.line;
2554
if (uint64_t(line.length()) <= maximum_line_length) {
2555
if (line.contains("export")) {
2556
line = reg_container.keyword_gdscript_export_single.sub(line, "@export", true);
2557
}
2558
if (line.contains("export")) {
2559
line = reg_container.keyword_gdscript_export_multi.sub(line, "$1@export", true);
2560
}
2561
if (line.contains("onready")) {
2562
line = reg_container.keyword_gdscript_onready.sub(line, "@onready", true);
2563
}
2564
if (line.contains("remote")) {
2565
line = reg_container.keyword_gdscript_remote.sub(line, builtin_escape("@rpc(\"any_peer\") func", builtin), true);
2566
}
2567
if (line.contains("remote")) {
2568
line = reg_container.keyword_gdscript_remotesync.sub(line, builtin_escape("@rpc(\"any_peer\", \"call_local\") func", builtin), true);
2569
}
2570
if (line.contains("sync")) {
2571
line = reg_container.keyword_gdscript_sync.sub(line, builtin_escape("@rpc(\"any_peer\", \"call_local\") func", builtin), true);
2572
}
2573
if (line.contains("slave")) {
2574
line = reg_container.keyword_gdscript_slave.sub(line, "@rpc func", true);
2575
}
2576
if (line.contains("puppet")) {
2577
line = reg_container.keyword_gdscript_puppet.sub(line, "@rpc func", true);
2578
}
2579
if (line.contains("puppet")) {
2580
line = reg_container.keyword_gdscript_puppetsync.sub(line, builtin_escape("@rpc(\"call_local\") func", builtin), true);
2581
}
2582
if (line.contains("master")) {
2583
line = reg_container.keyword_gdscript_master.sub(line, error_message + "@rpc func", true);
2584
}
2585
if (line.contains("master")) {
2586
line = reg_container.keyword_gdscript_mastersync.sub(line, error_message + builtin_escape("@rpc(\"call_local\") func", builtin), true);
2587
}
2588
}
2589
}
2590
}
2591
2592
Vector<String> ProjectConverter3To4::check_for_rename_gdscript_keywords(Vector<String> &lines, const RegExContainer &reg_container, bool builtin) {
2593
Vector<String> found_renames;
2594
2595
int current_line = 1;
2596
for (String &line : lines) {
2597
if (uint64_t(line.length()) <= maximum_line_length) {
2598
String old;
2599
2600
if (line.contains("tool")) {
2601
old = line;
2602
line = reg_container.keyword_gdscript_tool.sub(line, "@tool", true);
2603
if (old != line) {
2604
found_renames.append(line_formatter(current_line, "tool", "@tool", line));
2605
}
2606
}
2607
2608
if (line.contains("export")) {
2609
old = line;
2610
line = reg_container.keyword_gdscript_export_single.sub(line, "$1@export", true);
2611
if (old != line) {
2612
found_renames.append(line_formatter(current_line, "export", "@export", line));
2613
}
2614
}
2615
2616
if (line.contains("export")) {
2617
old = line;
2618
line = reg_container.keyword_gdscript_export_multi.sub(line, "@export", true);
2619
if (old != line) {
2620
found_renames.append(line_formatter(current_line, "export", "@export", line));
2621
}
2622
}
2623
2624
if (line.contains("onready")) {
2625
old = line;
2626
line = reg_container.keyword_gdscript_tool.sub(line, "@onready", true);
2627
if (old != line) {
2628
found_renames.append(line_formatter(current_line, "onready", "@onready", line));
2629
}
2630
}
2631
2632
if (line.contains("remote")) {
2633
old = line;
2634
line = reg_container.keyword_gdscript_remote.sub(line, builtin_escape("@rpc(\"any_peer\") func", builtin), true);
2635
if (old != line) {
2636
found_renames.append(line_formatter(current_line, "remote func", builtin_escape("@rpc(\"any_peer\") func", builtin), line));
2637
}
2638
}
2639
2640
if (line.contains("remote")) {
2641
old = line;
2642
line = reg_container.keyword_gdscript_remotesync.sub(line, builtin_escape("@rpc(\"any_peer\", \"call_local\")) func", builtin), true);
2643
if (old != line) {
2644
found_renames.append(line_formatter(current_line, "remotesync func", builtin_escape("@rpc(\"any_peer\", \"call_local\")) func", builtin), line));
2645
}
2646
}
2647
2648
if (line.contains("sync")) {
2649
old = line;
2650
line = reg_container.keyword_gdscript_sync.sub(line, builtin_escape("@rpc(\"any_peer\", \"call_local\")) func", builtin), true);
2651
if (old != line) {
2652
found_renames.append(line_formatter(current_line, "sync func", builtin_escape("@rpc(\"any_peer\", \"call_local\")) func", builtin), line));
2653
}
2654
}
2655
2656
if (line.contains("slave")) {
2657
old = line;
2658
line = reg_container.keyword_gdscript_slave.sub(line, "@rpc func", true);
2659
if (old != line) {
2660
found_renames.append(line_formatter(current_line, "slave func", "@rpc func", line));
2661
}
2662
}
2663
2664
if (line.contains("puppet")) {
2665
old = line;
2666
line = reg_container.keyword_gdscript_puppet.sub(line, "@rpc func", true);
2667
if (old != line) {
2668
found_renames.append(line_formatter(current_line, "puppet func", "@rpc func", line));
2669
}
2670
}
2671
2672
if (line.contains("puppet")) {
2673
old = line;
2674
line = reg_container.keyword_gdscript_puppetsync.sub(line, builtin_escape("@rpc(\"call_local\") func", builtin), true);
2675
if (old != line) {
2676
found_renames.append(line_formatter(current_line, "puppetsync func", builtin_escape("@rpc(\"call_local\") func", builtin), line));
2677
}
2678
}
2679
2680
if (line.contains("master")) {
2681
old = line;
2682
line = reg_container.keyword_gdscript_master.sub(line, "@rpc func", true);
2683
if (old != line) {
2684
found_renames.append(line_formatter(current_line, "master func", "@rpc func", line));
2685
}
2686
}
2687
2688
if (line.contains("master")) {
2689
old = line;
2690
line = reg_container.keyword_gdscript_master.sub(line, builtin_escape("@rpc(\"call_local\") func", builtin), true);
2691
if (old != line) {
2692
found_renames.append(line_formatter(current_line, "mastersync func", builtin_escape("@rpc(\"call_local\") func", builtin), line));
2693
}
2694
}
2695
}
2696
current_line++;
2697
}
2698
2699
return found_renames;
2700
}
2701
2702
void ProjectConverter3To4::rename_input_map_scancode(Vector<SourceLine> &source_lines, const RegExContainer &reg_container) {
2703
// The old Special Key, now colliding with CMD_OR_CTRL.
2704
const int old_spkey = (1 << 24);
2705
2706
for (SourceLine &source_line : source_lines) {
2707
if (source_line.is_comment) {
2708
continue;
2709
}
2710
2711
String &line = source_line.line;
2712
if (uint64_t(line.length()) <= maximum_line_length) {
2713
TypedArray<RegExMatch> reg_match = reg_container.input_map_keycode.search_all(line);
2714
2715
for (int i = 0; i < reg_match.size(); ++i) {
2716
Ref<RegExMatch> match = reg_match[i];
2717
PackedStringArray strings = match->get_strings();
2718
int key = strings[3].to_int();
2719
2720
if (key & old_spkey) {
2721
// Create new key, clearing old Special Key and setting new one.
2722
key = (key & ~old_spkey) | (int)Key::SPECIAL;
2723
2724
line = line.replace(strings[0], String(",\"") + strings[1] + "scancode\":" + String::num_int64(key));
2725
}
2726
}
2727
}
2728
}
2729
}
2730
2731
void ProjectConverter3To4::rename_joypad_buttons_and_axes(Vector<SourceLine> &source_lines, const RegExContainer &reg_container) {
2732
for (SourceLine &source_line : source_lines) {
2733
if (source_line.is_comment) {
2734
continue;
2735
}
2736
String &line = source_line.line;
2737
if (uint64_t(line.length()) <= maximum_line_length) {
2738
// Remap button indexes.
2739
TypedArray<RegExMatch> reg_match = reg_container.joypad_button_index.search_all(line);
2740
for (int i = 0; i < reg_match.size(); ++i) {
2741
Ref<RegExMatch> match = reg_match[i];
2742
PackedStringArray strings = match->get_strings();
2743
const String &button_index_entry = strings[0];
2744
int button_index_value = strings[1].to_int();
2745
if (button_index_value == 6) { // L2 and R2 are mapped to joypad axes in Godot 4.
2746
line = line.replace("InputEventJoypadButton", "InputEventJoypadMotion");
2747
line = line.replace(button_index_entry, ",\"axis\":4,\"axis_value\":1.0");
2748
} else if (button_index_value == 7) {
2749
line = line.replace("InputEventJoypadButton", "InputEventJoypadMotion");
2750
line = line.replace(button_index_entry, ",\"axis\":5,\"axis_value\":1.0");
2751
} else if (button_index_value < 22) { // There are no mappings for indexes greater than 22 in both Godot 3 & 4.
2752
const String &pressure_and_pressed_properties = strings[2];
2753
line = line.replace(button_index_entry, ",\"button_index\":" + String::num_int64(reg_container.joypad_button_mappings[button_index_value]) + "," + pressure_and_pressed_properties);
2754
}
2755
}
2756
// Remap axes. Only L2 and R2 need remapping.
2757
reg_match = reg_container.joypad_axis.search_all(line);
2758
for (int i = 0; i < reg_match.size(); ++i) {
2759
Ref<RegExMatch> match = reg_match[i];
2760
PackedStringArray strings = match->get_strings();
2761
const String &axis_entry = strings[0];
2762
int axis_value = strings[1].to_int();
2763
if (axis_value == 6) {
2764
line = line.replace(axis_entry, ",\"axis\":4");
2765
} else if (axis_value == 7) {
2766
line = line.replace(axis_entry, ",\"axis\":5");
2767
}
2768
}
2769
}
2770
}
2771
}
2772
2773
Vector<String> ProjectConverter3To4::check_for_rename_joypad_buttons_and_axes(Vector<String> &lines, const RegExContainer &reg_container) {
2774
Vector<String> found_renames;
2775
int current_line = 1;
2776
for (String &line : lines) {
2777
if (uint64_t(line.length()) <= maximum_line_length) {
2778
// Remap button indexes.
2779
TypedArray<RegExMatch> reg_match = reg_container.joypad_button_index.search_all(line);
2780
for (int i = 0; i < reg_match.size(); ++i) {
2781
Ref<RegExMatch> match = reg_match[i];
2782
PackedStringArray strings = match->get_strings();
2783
const String &button_index_entry = strings[0];
2784
int button_index_value = strings[1].to_int();
2785
if (button_index_value == 6) { // L2 and R2 are mapped to joypad axes in Godot 4.
2786
found_renames.append(line_formatter(current_line, "InputEventJoypadButton", "InputEventJoypadMotion", line));
2787
found_renames.append(line_formatter(current_line, button_index_entry, ",\"axis\":4", line));
2788
} else if (button_index_value == 7) {
2789
found_renames.append(line_formatter(current_line, "InputEventJoypadButton", "InputEventJoypadMotion", line));
2790
found_renames.append(line_formatter(current_line, button_index_entry, ",\"axis\":5", line));
2791
} else if (button_index_value < 22) { // There are no mappings for indexes greater than 22 in both Godot 3 & 4.
2792
found_renames.append(line_formatter(current_line, "\"button_index\":" + strings[1], "\"button_index\":" + String::num_int64(reg_container.joypad_button_mappings[button_index_value]), line));
2793
}
2794
}
2795
// Remap axes. Only L2 and R2 need remapping.
2796
reg_match = reg_container.joypad_axis.search_all(line);
2797
for (int i = 0; i < reg_match.size(); ++i) {
2798
Ref<RegExMatch> match = reg_match[i];
2799
PackedStringArray strings = match->get_strings();
2800
const String &axis_entry = strings[0];
2801
int axis_value = strings[1].to_int();
2802
if (axis_value == 6) {
2803
found_renames.append(line_formatter(current_line, axis_entry, ",\"axis\":4", line));
2804
} else if (axis_value == 7) {
2805
found_renames.append(line_formatter(current_line, axis_entry, ",\"axis\":5", line));
2806
}
2807
}
2808
current_line++;
2809
}
2810
}
2811
return found_renames;
2812
}
2813
2814
Vector<String> ProjectConverter3To4::check_for_rename_input_map_scancode(Vector<String> &lines, const RegExContainer &reg_container) {
2815
Vector<String> found_renames;
2816
2817
// The old Special Key, now colliding with CMD_OR_CTRL.
2818
const int old_spkey = (1 << 24);
2819
2820
int current_line = 1;
2821
for (String &line : lines) {
2822
if (uint64_t(line.length()) <= maximum_line_length) {
2823
TypedArray<RegExMatch> reg_match = reg_container.input_map_keycode.search_all(line);
2824
2825
for (int i = 0; i < reg_match.size(); ++i) {
2826
Ref<RegExMatch> match = reg_match[i];
2827
PackedStringArray strings = match->get_strings();
2828
int key = strings[3].to_int();
2829
2830
if (key & old_spkey) {
2831
// Create new key, clearing old Special Key and setting new one.
2832
key = (key & ~old_spkey) | (int)Key::SPECIAL;
2833
2834
found_renames.append(line_formatter(current_line, strings[3], String::num_int64(key), line));
2835
}
2836
}
2837
}
2838
current_line++;
2839
}
2840
return found_renames;
2841
}
2842
2843
void ProjectConverter3To4::rename_animation_suffixes(Vector<SourceLine> &source_lines, const RegExContainer &reg_container) {
2844
for (SourceLine &source_line : source_lines) {
2845
if (source_line.is_comment) {
2846
continue;
2847
}
2848
String &line = source_line.line;
2849
if (uint64_t(line.length()) <= maximum_line_length) {
2850
TypedArray<RegExMatch> reg_match = reg_container.animation_suffix.search_all(line);
2851
for (int i = 0; i < reg_match.size(); ++i) {
2852
Ref<RegExMatch> match = reg_match[i];
2853
PackedStringArray strings = match->get_strings();
2854
String replacement = strings[1] + strings[2] + strings[4];
2855
line = line.replace(strings[0], replacement);
2856
}
2857
}
2858
}
2859
}
2860
2861
Vector<String> ProjectConverter3To4::check_for_rename_animation_suffixes(Vector<String> &lines, const RegExContainer &reg_container) {
2862
Vector<String> found_renames;
2863
int current_line = 1;
2864
2865
for (String &line : lines) {
2866
if (uint64_t(line.length()) <= maximum_line_length) {
2867
TypedArray<RegExMatch> reg_match = reg_container.animation_suffix.search_all(line);
2868
for (int i = 0; i < reg_match.size(); ++i) {
2869
Ref<RegExMatch> match = reg_match[i];
2870
PackedStringArray strings = match->get_strings();
2871
String replacement = strings[1] + strings[2] + strings[4];
2872
found_renames.append(line_formatter(current_line, strings[0], replacement, line));
2873
}
2874
}
2875
current_line++;
2876
}
2877
return found_renames;
2878
}
2879
2880
void ProjectConverter3To4::custom_rename(Vector<SourceLine> &source_lines, const String &from, const String &to) {
2881
RegEx reg = RegEx(String("\\b") + from + "\\b");
2882
CRASH_COND(!reg.is_valid());
2883
for (SourceLine &source_line : source_lines) {
2884
if (source_line.is_comment) {
2885
continue;
2886
}
2887
2888
String &line = source_line.line;
2889
if (uint64_t(line.length()) <= maximum_line_length) {
2890
line = reg.sub(line, to, true);
2891
}
2892
}
2893
}
2894
2895
Vector<String> ProjectConverter3To4::check_for_custom_rename(Vector<String> &lines, const String &from, const String &to) {
2896
Vector<String> found_renames;
2897
2898
RegEx reg = RegEx(String("\\b") + from + "\\b");
2899
CRASH_COND(!reg.is_valid());
2900
2901
int current_line = 1;
2902
for (String &line : lines) {
2903
if (uint64_t(line.length()) <= maximum_line_length) {
2904
TypedArray<RegExMatch> reg_match = reg.search_all(line);
2905
if (reg_match.size() > 0) {
2906
found_renames.append(line_formatter(current_line, from.replace("\\.", "."), to, line)); // Without replacing it will print "\.shader" instead ".shader".
2907
}
2908
}
2909
current_line++;
2910
}
2911
return found_renames;
2912
}
2913
2914
void ProjectConverter3To4::rename_common(const char *array[][2], LocalVector<RegEx *> &cached_regexes, Vector<SourceLine> &source_lines) {
2915
for (SourceLine &source_line : source_lines) {
2916
if (source_line.is_comment) {
2917
continue;
2918
}
2919
2920
String &line = source_line.line;
2921
if (uint64_t(line.length()) <= maximum_line_length) {
2922
for (unsigned int current_index = 0; current_index < cached_regexes.size(); current_index++) {
2923
if (line.contains(array[current_index][0])) {
2924
line = cached_regexes[current_index]->sub(line, array[current_index][1], true);
2925
}
2926
}
2927
}
2928
}
2929
}
2930
2931
Vector<String> ProjectConverter3To4::check_for_rename_common(const char *array[][2], LocalVector<RegEx *> &cached_regexes, Vector<String> &lines) {
2932
Vector<String> found_renames;
2933
2934
int current_line = 1;
2935
2936
for (String &line : lines) {
2937
if (uint64_t(line.length()) <= maximum_line_length) {
2938
for (unsigned int current_index = 0; current_index < cached_regexes.size(); current_index++) {
2939
if (line.contains(array[current_index][0])) {
2940
TypedArray<RegExMatch> reg_match = cached_regexes[current_index]->search_all(line);
2941
if (reg_match.size() > 0) {
2942
found_renames.append(line_formatter(current_line, array[current_index][0], array[current_index][1], line));
2943
}
2944
}
2945
}
2946
}
2947
current_line++;
2948
}
2949
2950
return found_renames;
2951
}
2952
2953
// Prints full info about renamed things e.g.:
2954
// Line (67) remove -> remove_at - LINE """ doubler._blacklist.remove(0) """
2955
String ProjectConverter3To4::line_formatter(int current_line, String from, String to, String line) {
2956
if (from.size() > 200) {
2957
from = from.substr(0, 197) + "...";
2958
}
2959
if (to.size() > 200) {
2960
to = to.substr(0, 197) + "...";
2961
}
2962
if (line.size() > 400) {
2963
line = line.substr(0, 397) + "...";
2964
}
2965
2966
from = from.strip_escapes();
2967
to = to.strip_escapes();
2968
line = line.remove_chars("\r\n").strip_edges();
2969
2970
return vformat("Line(%d), %s -> %s - LINE \"\"\" %s \"\"\"", current_line, from, to, line);
2971
}
2972
2973
// Prints only full lines e.g.:
2974
// Line (1) - FULL LINES - """yield(get_tree().create_timer(3), 'timeout')""" =====> """ await get_tree().create_timer(3).timeout """
2975
String ProjectConverter3To4::simple_line_formatter(int current_line, String old_line, String new_line) {
2976
if (old_line.size() > 1000) {
2977
old_line = old_line.substr(0, 997) + "...";
2978
}
2979
if (new_line.size() > 1000) {
2980
new_line = new_line.substr(0, 997) + "...";
2981
}
2982
2983
old_line = old_line.remove_chars("\r\n").strip_edges();
2984
new_line = new_line.remove_chars("\r\n").strip_edges();
2985
2986
return vformat("Line (%d) - FULL LINES - \"\"\" %s \"\"\" =====> \"\"\" %s \"\"\"", current_line, old_line, new_line);
2987
}
2988
2989
// Collects string from vector strings
2990
String ProjectConverter3To4::collect_string_from_vector(Vector<SourceLine> &vector) {
2991
String string = "";
2992
for (int i = 0; i < vector.size(); i++) {
2993
string += vector[i].line;
2994
2995
if (i != vector.size() - 1) {
2996
string += "\n";
2997
}
2998
}
2999
return string;
3000
}
3001
3002
#endif // DISABLE_DEPRECATED
3003
3004