project_converter_3_to_4.cpp 144 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783
  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. #include "project_converter_3_to_4.h"
  31. #ifndef DISABLE_DEPRECATED
  32. #include "modules/modules_enabled.gen.h" // For regex.
  33. #ifdef MODULE_REGEX_ENABLED
  34. #include "core/error/error_macros.h"
  35. #include "core/io/dir_access.h"
  36. #include "core/io/file_access.h"
  37. #include "core/object/ref_counted.h"
  38. #include "core/os/time.h"
  39. #include "core/templates/hash_map.h"
  40. #include "core/templates/list.h"
  41. #include "editor/renames_map_3_to_4.h"
  42. #include "modules/regex/regex.h"
  43. // Find "OS.set_property(x)", capturing x into $1.
  44. static String make_regex_gds_os_property_set(String name_set) {
  45. return String("\\bOS\\.") + name_set + "\\s*\\((.*)\\)";
  46. }
  47. // Find "OS.property = x", capturing x into $1 or $2.
  48. static String make_regex_gds_os_property_assign(String name) {
  49. return String("\\bOS\\.") + name + "\\s*=\\s*([^#]+)";
  50. }
  51. // Find "OS.property" OR "OS.get_property()" / "OS.is_property()".
  52. static String make_regex_gds_os_property_get(String name, String get) {
  53. return String("\\bOS\\.(") + get + "_)?" + name + "(\\s*\\(\\s*\\))?";
  54. }
  55. class ProjectConverter3To4::RegExContainer {
  56. public:
  57. // Custom GDScript.
  58. RegEx reg_is_empty = RegEx("\\bempty\\(");
  59. RegEx reg_super = RegEx("([\t ])\\.([a-zA-Z_])");
  60. RegEx reg_json_to = RegEx("\\bto_json\\b");
  61. RegEx reg_json_parse = RegEx("([\t ]{0,})([^\n]+)parse_json\\(([^\n]+)");
  62. RegEx reg_json_non_new = RegEx("([\t ]{0,})([^\n]+)JSON\\.parse\\(([^\n]+)");
  63. RegEx reg_json_print = RegEx("\\bJSON\\b\\.print\\(");
  64. RegEx reg_export = RegEx("export\\(([a-zA-Z0-9_]+)\\)[ ]+var[ ]+([a-zA-Z0-9_]+)");
  65. RegEx reg_export_advanced = RegEx("export\\(([^)^\n]+)\\)[ ]+var[ ]+([a-zA-Z0-9_]+)([^\n]+)");
  66. RegEx reg_setget_setget = RegEx("var[ ]+([a-zA-Z0-9_]+)([^\n]+?)[ \t]*setget[ \t]+([a-zA-Z0-9_]+)[ \t]*,[ \t]*([a-zA-Z0-9_]+)");
  67. RegEx reg_setget_set = RegEx("var[ ]+([a-zA-Z0-9_]+)([^\n]+?)[ \t]*setget[ \t]+([a-zA-Z0-9_]+)[ \t]*[,]*[^\n]*$");
  68. RegEx reg_setget_get = RegEx("var[ ]+([a-zA-Z0-9_]+)([^\n]+?)[ \t]*setget[ \t]+,[ \t]*([a-zA-Z0-9_]+)[ \t]*$");
  69. RegEx reg_join = RegEx("([\\(\\)a-zA-Z0-9_]+)\\.join\\(([^\n^\\)]+)\\)");
  70. RegEx reg_image_lock = RegEx("([a-zA-Z0-9_\\.]+)\\.lock\\(\\)");
  71. RegEx reg_image_unlock = RegEx("([a-zA-Z0-9_\\.]+)\\.unlock\\(\\)");
  72. RegEx reg_instantiate = RegEx("\\.instance\\(([^\\)]*)\\)");
  73. // Simple OS properties with getters/setters.
  74. RegEx reg_os_current_screen = RegEx("\\bOS\\.((set_|get_)?)current_screen\\b");
  75. RegEx reg_os_min_window_size = RegEx("\\bOS\\.((set_|get_)?)min_window_size\\b");
  76. RegEx reg_os_max_window_size = RegEx("\\bOS\\.((set_|get_)?)max_window_size\\b");
  77. RegEx reg_os_window_position = RegEx("\\bOS\\.((set_|get_)?)window_position\\b");
  78. RegEx reg_os_window_size = RegEx("\\bOS\\.((set_|get_)?)window_size\\b");
  79. RegEx reg_os_getset_screen_orient = RegEx("\\bOS\\.(s|g)et_screen_orientation\\b");
  80. // OS property getters/setters for non trivial replacements.
  81. RegEx reg_os_set_window_resizable = RegEx(make_regex_gds_os_property_set("set_window_resizable"));
  82. RegEx reg_os_assign_window_resizable = RegEx(make_regex_gds_os_property_assign("window_resizable"));
  83. RegEx reg_os_is_window_resizable = RegEx(make_regex_gds_os_property_get("window_resizable", "is"));
  84. RegEx reg_os_set_fullscreen = RegEx(make_regex_gds_os_property_set("set_window_fullscreen"));
  85. RegEx reg_os_assign_fullscreen = RegEx(make_regex_gds_os_property_assign("window_fullscreen"));
  86. RegEx reg_os_is_fullscreen = RegEx(make_regex_gds_os_property_get("window_fullscreen", "is"));
  87. RegEx reg_os_set_maximized = RegEx(make_regex_gds_os_property_set("set_window_maximized"));
  88. RegEx reg_os_assign_maximized = RegEx(make_regex_gds_os_property_assign("window_maximized"));
  89. RegEx reg_os_is_maximized = RegEx(make_regex_gds_os_property_get("window_maximized", "is"));
  90. RegEx reg_os_set_minimized = RegEx(make_regex_gds_os_property_set("set_window_minimized"));
  91. RegEx reg_os_assign_minimized = RegEx(make_regex_gds_os_property_assign("window_minimized"));
  92. RegEx reg_os_is_minimized = RegEx(make_regex_gds_os_property_get("window_minimized", "is"));
  93. RegEx reg_os_set_vsync = RegEx(make_regex_gds_os_property_set("set_use_vsync"));
  94. RegEx reg_os_assign_vsync = RegEx(make_regex_gds_os_property_assign("vsync_enabled"));
  95. RegEx reg_os_is_vsync = RegEx(make_regex_gds_os_property_get("vsync_enabled", "is"));
  96. // OS properties specific cases & specific replacements.
  97. RegEx reg_os_assign_screen_orient = RegEx("^(\\s*)OS\\.screen_orientation\\s*=\\s*([^#]+)"); // $1 - indent, $2 - value
  98. RegEx reg_os_set_always_on_top = RegEx(make_regex_gds_os_property_set("set_window_always_on_top"));
  99. RegEx reg_os_is_always_on_top = RegEx("\\bOS\\.is_window_always_on_top\\s*\\(.*\\)");
  100. RegEx reg_os_set_borderless = RegEx(make_regex_gds_os_property_set("set_borderless_window"));
  101. RegEx reg_os_get_borderless = RegEx("\\bOS\\.get_borderless_window\\s*\\(\\s*\\)");
  102. RegEx reg_os_screen_orient_enum = RegEx("\\bOS\\.SCREEN_ORIENTATION_(\\w+)\\b"); // $1 - constant suffix
  103. // GDScript keywords.
  104. RegEx keyword_gdscript_tool = RegEx("^tool");
  105. RegEx keyword_gdscript_export_single = RegEx("^export");
  106. RegEx keyword_gdscript_export_mutli = RegEx("([\t]+)export\\b");
  107. RegEx keyword_gdscript_onready = RegEx("^onready");
  108. RegEx keyword_gdscript_remote = RegEx("^remote func");
  109. RegEx keyword_gdscript_remotesync = RegEx("^remotesync func");
  110. RegEx keyword_gdscript_sync = RegEx("^sync func");
  111. RegEx keyword_gdscript_slave = RegEx("^slave func");
  112. RegEx keyword_gdscript_puppet = RegEx("^puppet func");
  113. RegEx keyword_gdscript_puppetsync = RegEx("^puppetsync func");
  114. RegEx keyword_gdscript_master = RegEx("^master func");
  115. RegEx keyword_gdscript_mastersync = RegEx("^mastersync func");
  116. RegEx gdscript_comment = RegEx("^\\s*#");
  117. RegEx csharp_comment = RegEx("^\\s*\\/\\/");
  118. // CSharp keywords.
  119. RegEx keyword_csharp_remote = RegEx("\\[Remote(Attribute)?(\\(\\))?\\]");
  120. RegEx keyword_csharp_remotesync = RegEx("\\[(Remote)?Sync(Attribute)?(\\(\\))?\\]");
  121. RegEx keyword_csharp_puppet = RegEx("\\[(Puppet|Slave)(Attribute)?(\\(\\))?\\]");
  122. RegEx keyword_csharp_puppetsync = RegEx("\\[PuppetSync(Attribute)?(\\(\\))?\\]");
  123. RegEx keyword_csharp_master = RegEx("\\[Master(Attribute)?(\\(\\))?\\]");
  124. RegEx keyword_csharp_mastersync = RegEx("\\[MasterSync(Attribute)?(\\(\\))?\\]");
  125. // Colors.
  126. LocalVector<RegEx *> color_regexes;
  127. LocalVector<String> color_renamed;
  128. // Classes.
  129. LocalVector<RegEx *> class_tscn_regexes;
  130. LocalVector<RegEx *> class_gd_regexes;
  131. LocalVector<RegEx *> class_shader_regexes;
  132. // Keycode.
  133. RegEx input_map_keycode = RegEx("\\b,\"((physical_)?)scancode\":(\\d+)\\b");
  134. LocalVector<RegEx *> class_regexes;
  135. RegEx class_temp_tscn = RegEx("\\bTEMP_RENAMED_CLASS.tscn\\b");
  136. RegEx class_temp_gd = RegEx("\\bTEMP_RENAMED_CLASS.gd\\b");
  137. RegEx class_temp_shader = RegEx("\\bTEMP_RENAMED_CLASS.shader\\b");
  138. LocalVector<String> class_temp_tscn_renames;
  139. LocalVector<String> class_temp_gd_renames;
  140. LocalVector<String> class_temp_shader_renames;
  141. // Common.
  142. LocalVector<RegEx *> enum_regexes;
  143. LocalVector<RegEx *> gdscript_function_regexes;
  144. LocalVector<RegEx *> project_settings_regexes;
  145. LocalVector<RegEx *> project_godot_regexes;
  146. LocalVector<RegEx *> input_map_regexes;
  147. LocalVector<RegEx *> gdscript_properties_regexes;
  148. LocalVector<RegEx *> gdscript_signals_regexes;
  149. LocalVector<RegEx *> shaders_regexes;
  150. LocalVector<RegEx *> builtin_types_regexes;
  151. LocalVector<RegEx *> theme_override_regexes;
  152. LocalVector<RegEx *> csharp_function_regexes;
  153. LocalVector<RegEx *> csharp_properties_regexes;
  154. LocalVector<RegEx *> csharp_signal_regexes;
  155. RegExContainer() {
  156. // Common.
  157. {
  158. // Enum.
  159. for (unsigned int current_index = 0; RenamesMap3To4::enum_renames[current_index][0]; current_index++) {
  160. enum_regexes.push_back(memnew(RegEx(String("\\b") + RenamesMap3To4::enum_renames[current_index][0] + "\\b")));
  161. }
  162. // GDScript functions.
  163. for (unsigned int current_index = 0; RenamesMap3To4::gdscript_function_renames[current_index][0]; current_index++) {
  164. gdscript_function_regexes.push_back(memnew(RegEx(String("\\b") + RenamesMap3To4::gdscript_function_renames[current_index][0] + "\\b")));
  165. }
  166. // Project Settings in scripts.
  167. for (unsigned int current_index = 0; RenamesMap3To4::project_settings_renames[current_index][0]; current_index++) {
  168. project_settings_regexes.push_back(memnew(RegEx(String("\\b") + RenamesMap3To4::project_settings_renames[current_index][0] + "\\b")));
  169. }
  170. // Project Settings in project.godot.
  171. for (unsigned int current_index = 0; RenamesMap3To4::project_godot_renames[current_index][0]; current_index++) {
  172. project_godot_regexes.push_back(memnew(RegEx(String("\\b") + RenamesMap3To4::project_godot_renames[current_index][0] + "\\b")));
  173. }
  174. // Input Map.
  175. for (unsigned int current_index = 0; RenamesMap3To4::input_map_renames[current_index][0]; current_index++) {
  176. input_map_regexes.push_back(memnew(RegEx(String("\\b") + RenamesMap3To4::input_map_renames[current_index][0] + "\\b")));
  177. }
  178. // GDScript properties.
  179. for (unsigned int current_index = 0; RenamesMap3To4::gdscript_properties_renames[current_index][0]; current_index++) {
  180. gdscript_properties_regexes.push_back(memnew(RegEx(String("\\b") + RenamesMap3To4::gdscript_properties_renames[current_index][0] + "\\b")));
  181. }
  182. // GDScript Signals.
  183. for (unsigned int current_index = 0; RenamesMap3To4::gdscript_signals_renames[current_index][0]; current_index++) {
  184. gdscript_signals_regexes.push_back(memnew(RegEx(String("\\b") + RenamesMap3To4::gdscript_signals_renames[current_index][0] + "\\b")));
  185. }
  186. // Shaders.
  187. for (unsigned int current_index = 0; RenamesMap3To4::shaders_renames[current_index][0]; current_index++) {
  188. shaders_regexes.push_back(memnew(RegEx(String("\\b") + RenamesMap3To4::shaders_renames[current_index][0] + "\\b")));
  189. }
  190. // Builtin types.
  191. for (unsigned int current_index = 0; RenamesMap3To4::builtin_types_renames[current_index][0]; current_index++) {
  192. builtin_types_regexes.push_back(memnew(RegEx(String("\\b") + RenamesMap3To4::builtin_types_renames[current_index][0] + "\\b")));
  193. }
  194. // Theme overrides.
  195. for (unsigned int current_index = 0; RenamesMap3To4::theme_override_renames[current_index][0]; current_index++) {
  196. theme_override_regexes.push_back(memnew(RegEx(String("\\b") + RenamesMap3To4::theme_override_renames[current_index][0] + "\\b")));
  197. }
  198. // CSharp function renames.
  199. for (unsigned int current_index = 0; RenamesMap3To4::csharp_function_renames[current_index][0]; current_index++) {
  200. csharp_function_regexes.push_back(memnew(RegEx(String("\\b") + RenamesMap3To4::csharp_function_renames[current_index][0] + "\\b")));
  201. }
  202. // CSharp properties renames.
  203. for (unsigned int current_index = 0; RenamesMap3To4::csharp_properties_renames[current_index][0]; current_index++) {
  204. csharp_properties_regexes.push_back(memnew(RegEx(String("\\b") + RenamesMap3To4::csharp_properties_renames[current_index][0] + "\\b")));
  205. }
  206. // CSharp signals renames.
  207. for (unsigned int current_index = 0; RenamesMap3To4::csharp_signals_renames[current_index][0]; current_index++) {
  208. csharp_signal_regexes.push_back(memnew(RegEx(String("\\b") + RenamesMap3To4::csharp_signals_renames[current_index][0] + "\\b")));
  209. }
  210. }
  211. // Colors.
  212. {
  213. for (unsigned int current_index = 0; RenamesMap3To4::color_renames[current_index][0]; current_index++) {
  214. color_regexes.push_back(memnew(RegEx(String("\\bColor.") + RenamesMap3To4::color_renames[current_index][0] + "\\b")));
  215. color_renamed.push_back(String("Color.") + RenamesMap3To4::color_renames[current_index][1]);
  216. }
  217. }
  218. // Classes.
  219. {
  220. for (unsigned int current_index = 0; RenamesMap3To4::class_renames[current_index][0]; current_index++) {
  221. const String class_name = RenamesMap3To4::class_renames[current_index][0];
  222. class_tscn_regexes.push_back(memnew(RegEx(String("\\b") + class_name + ".tscn\\b")));
  223. class_gd_regexes.push_back(memnew(RegEx(String("\\b") + class_name + ".gd\\b")));
  224. class_shader_regexes.push_back(memnew(RegEx(String("\\b") + class_name + ".shader\\b")));
  225. class_regexes.push_back(memnew(RegEx(String("\\b") + class_name + "\\b")));
  226. class_temp_tscn_renames.push_back(class_name + ".tscn");
  227. class_temp_gd_renames.push_back(class_name + ".gd");
  228. class_temp_shader_renames.push_back(class_name + ".shader");
  229. }
  230. }
  231. }
  232. ~RegExContainer() {
  233. for (RegEx *regex : color_regexes) {
  234. memdelete(regex);
  235. }
  236. for (unsigned int i = 0; i < class_tscn_regexes.size(); i++) {
  237. memdelete(class_tscn_regexes[i]);
  238. memdelete(class_gd_regexes[i]);
  239. memdelete(class_shader_regexes[i]);
  240. memdelete(class_regexes[i]);
  241. }
  242. for (RegEx *regex : enum_regexes) {
  243. memdelete(regex);
  244. }
  245. for (RegEx *regex : gdscript_function_regexes) {
  246. memdelete(regex);
  247. }
  248. for (RegEx *regex : project_settings_regexes) {
  249. memdelete(regex);
  250. }
  251. for (RegEx *regex : project_godot_regexes) {
  252. memdelete(regex);
  253. }
  254. for (RegEx *regex : input_map_regexes) {
  255. memdelete(regex);
  256. }
  257. for (RegEx *regex : gdscript_properties_regexes) {
  258. memdelete(regex);
  259. }
  260. for (RegEx *regex : gdscript_signals_regexes) {
  261. memdelete(regex);
  262. }
  263. for (RegEx *regex : shaders_regexes) {
  264. memdelete(regex);
  265. }
  266. for (RegEx *regex : builtin_types_regexes) {
  267. memdelete(regex);
  268. }
  269. for (RegEx *regex : theme_override_regexes) {
  270. memdelete(regex);
  271. }
  272. for (RegEx *regex : csharp_function_regexes) {
  273. memdelete(regex);
  274. }
  275. for (RegEx *regex : csharp_properties_regexes) {
  276. memdelete(regex);
  277. }
  278. for (RegEx *regex : csharp_signal_regexes) {
  279. memdelete(regex);
  280. }
  281. }
  282. };
  283. ProjectConverter3To4::ProjectConverter3To4(int p_maximum_file_size_kb, int p_maximum_line_length) {
  284. maximum_file_size = p_maximum_file_size_kb * 1024;
  285. maximum_line_length = p_maximum_line_length;
  286. }
  287. // Function responsible for converting project.
  288. bool ProjectConverter3To4::convert() {
  289. print_line("Starting conversion.");
  290. uint64_t conversion_start_time = Time::get_singleton()->get_ticks_msec();
  291. RegExContainer reg_container = RegExContainer();
  292. int cached_maximum_line_length = maximum_line_length;
  293. maximum_line_length = 10000; // Use only for tests bigger value, to not break them.
  294. ERR_FAIL_COND_V_MSG(!test_array_names(), false, "Cannot start converting due to problems with data in arrays.");
  295. ERR_FAIL_COND_V_MSG(!test_conversion(reg_container), false, "Aborting conversion due to validation tests failing");
  296. maximum_line_length = cached_maximum_line_length;
  297. // Checking if folder contains valid Godot 3 project.
  298. // Project should not be converted more than once.
  299. {
  300. String converter_text = "; Project was converted by built-in tool to Godot 4.0";
  301. 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.");
  302. Error err = OK;
  303. String project_godot_content = FileAccess::get_file_as_string("project.godot", &err);
  304. ERR_FAIL_COND_V_MSG(err != OK, false, "Unable to read \"project.godot\".");
  305. ERR_FAIL_COND_V_MSG(project_godot_content.contains(converter_text), false, "Project was already converted with this tool.");
  306. Ref<FileAccess> file = FileAccess::open("project.godot", FileAccess::WRITE);
  307. ERR_FAIL_COND_V_MSG(file.is_null(), false, "Unable to open \"project.godot\".");
  308. file->store_string(converter_text + "\n" + project_godot_content);
  309. }
  310. Vector<String> collected_files = check_for_files();
  311. uint32_t converted_files = 0;
  312. // Check file by file.
  313. for (int i = 0; i < collected_files.size(); i++) {
  314. String file_name = collected_files[i];
  315. Vector<SourceLine> source_lines;
  316. uint32_t ignored_lines = 0;
  317. {
  318. Ref<FileAccess> file = FileAccess::open(file_name, FileAccess::READ);
  319. ERR_CONTINUE_MSG(file.is_null(), vformat("Unable to read content of \"%s\".", file_name));
  320. while (!file->eof_reached()) {
  321. String line = file->get_line();
  322. SourceLine source_line;
  323. source_line.line = line;
  324. source_line.is_comment = reg_container.gdscript_comment.search_all(line).size() > 0 || reg_container.csharp_comment.search_all(line).size() > 0;
  325. source_lines.append(source_line);
  326. }
  327. }
  328. String file_content_before = collect_string_from_vector(source_lines);
  329. uint64_t hash_before = file_content_before.hash();
  330. uint64_t file_size = file_content_before.size();
  331. 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));
  332. Vector<String> reason;
  333. bool is_ignored = false;
  334. uint64_t start_time = Time::get_singleton()->get_ticks_msec();
  335. if (file_name.ends_with(".shader")) {
  336. DirAccess::remove_file_or_error(file_name.trim_prefix("res://"));
  337. file_name = file_name.replace(".shader", ".gdshader");
  338. }
  339. if (file_size < uint64_t(maximum_file_size)) {
  340. // ".tscn" must work exactly the same as ".gd" files because they may contain built-in Scripts.
  341. if (file_name.ends_with(".gd")) {
  342. fix_tool_declaration(source_lines, reg_container);
  343. rename_classes(source_lines, reg_container); // Using only specialized function.
  344. rename_common(RenamesMap3To4::enum_renames, reg_container.enum_regexes, source_lines);
  345. rename_colors(source_lines, reg_container); // Require to additional rename.
  346. rename_common(RenamesMap3To4::gdscript_function_renames, reg_container.gdscript_function_regexes, source_lines);
  347. rename_gdscript_functions(source_lines, reg_container, false); // Require to additional rename.
  348. rename_common(RenamesMap3To4::project_settings_renames, reg_container.project_settings_regexes, source_lines);
  349. rename_gdscript_keywords(source_lines, reg_container);
  350. rename_common(RenamesMap3To4::gdscript_properties_renames, reg_container.gdscript_properties_regexes, source_lines);
  351. rename_common(RenamesMap3To4::gdscript_signals_renames, reg_container.gdscript_signals_regexes, source_lines);
  352. rename_common(RenamesMap3To4::shaders_renames, reg_container.shaders_regexes, source_lines);
  353. rename_common(RenamesMap3To4::builtin_types_renames, reg_container.builtin_types_regexes, source_lines);
  354. rename_common(RenamesMap3To4::theme_override_renames, reg_container.theme_override_regexes, source_lines);
  355. custom_rename(source_lines, "\\.shader", ".gdshader");
  356. } else if (file_name.ends_with(".tscn")) {
  357. rename_classes(source_lines, reg_container); // Using only specialized function.
  358. rename_common(RenamesMap3To4::enum_renames, reg_container.enum_regexes, source_lines);
  359. rename_colors(source_lines, reg_container); // Require to do additional renames.
  360. rename_common(RenamesMap3To4::gdscript_function_renames, reg_container.gdscript_function_regexes, source_lines);
  361. rename_gdscript_functions(source_lines, reg_container, true); // Require to do additional renames.
  362. rename_common(RenamesMap3To4::project_settings_renames, reg_container.project_settings_regexes, source_lines);
  363. rename_gdscript_keywords(source_lines, reg_container);
  364. rename_common(RenamesMap3To4::gdscript_properties_renames, reg_container.gdscript_properties_regexes, source_lines);
  365. rename_common(RenamesMap3To4::gdscript_signals_renames, reg_container.gdscript_signals_regexes, source_lines);
  366. rename_common(RenamesMap3To4::shaders_renames, reg_container.shaders_regexes, source_lines);
  367. rename_common(RenamesMap3To4::builtin_types_renames, reg_container.builtin_types_regexes, source_lines);
  368. rename_common(RenamesMap3To4::theme_override_renames, reg_container.theme_override_regexes, source_lines);
  369. custom_rename(source_lines, "\\.shader", ".gdshader");
  370. } else if (file_name.ends_with(".cs")) { // TODO, C# should use different methods.
  371. rename_classes(source_lines, reg_container); // Using only specialized function.
  372. rename_common(RenamesMap3To4::csharp_function_renames, reg_container.csharp_function_regexes, source_lines);
  373. rename_common(RenamesMap3To4::builtin_types_renames, reg_container.builtin_types_regexes, source_lines);
  374. rename_common(RenamesMap3To4::csharp_properties_renames, reg_container.csharp_properties_regexes, source_lines);
  375. rename_common(RenamesMap3To4::csharp_signals_renames, reg_container.csharp_signal_regexes, source_lines);
  376. rename_csharp_functions(source_lines, reg_container);
  377. rename_csharp_attributes(source_lines, reg_container);
  378. custom_rename(source_lines, "public class ", "public partial class ");
  379. } else if (file_name.ends_with(".gdshader") || file_name.ends_with(".shader")) {
  380. rename_common(RenamesMap3To4::shaders_renames, reg_container.shaders_regexes, source_lines);
  381. } else if (file_name.ends_with("tres")) {
  382. rename_classes(source_lines, reg_container); // Using only specialized function.
  383. rename_common(RenamesMap3To4::shaders_renames, reg_container.shaders_regexes, source_lines);
  384. rename_common(RenamesMap3To4::builtin_types_renames, reg_container.builtin_types_regexes, source_lines);
  385. custom_rename(source_lines, "\\.shader", ".gdshader");
  386. } else if (file_name.ends_with("project.godot")) {
  387. rename_common(RenamesMap3To4::project_godot_renames, reg_container.project_godot_regexes, source_lines);
  388. rename_common(RenamesMap3To4::builtin_types_renames, reg_container.builtin_types_regexes, source_lines);
  389. rename_input_map_scancode(source_lines, reg_container);
  390. rename_common(RenamesMap3To4::input_map_renames, reg_container.input_map_regexes, source_lines);
  391. } else if (file_name.ends_with(".csproj")) {
  392. // TODO
  393. } else if (file_name.ends_with(".import")) {
  394. for (SourceLine &source_line : source_lines) {
  395. String &line = source_line.line;
  396. if (line.contains("nodes/root_type=\"Spatial\"")) {
  397. line = "nodes/root_type=\"Node3D\"";
  398. }
  399. }
  400. } else {
  401. ERR_PRINT(file_name + " is not supported!");
  402. continue;
  403. }
  404. for (SourceLine &source_line : source_lines) {
  405. if (source_line.is_comment) {
  406. continue;
  407. }
  408. String &line = source_line.line;
  409. if (uint64_t(line.length()) > maximum_line_length) {
  410. ignored_lines += 1;
  411. }
  412. }
  413. } else {
  414. reason.append(vformat(" ERROR: File has exceeded the maximum size allowed - %d KB", maximum_file_size / 1024));
  415. is_ignored = true;
  416. }
  417. uint64_t end_time = Time::get_singleton()->get_ticks_msec();
  418. if (is_ignored) {
  419. String end_message = vformat(" Checking file took %d ms.", end_time - start_time);
  420. print_line(end_message);
  421. } else {
  422. String file_content_after = collect_string_from_vector(source_lines);
  423. uint64_t hash_after = file_content_after.hash64();
  424. // Don't need to save file without any changes.
  425. // Save if this is a shader, because it was renamed.
  426. if (hash_before != hash_after || file_name.ends_with(".gdshader")) {
  427. converted_files++;
  428. Ref<FileAccess> file = FileAccess::open(file_name, FileAccess::WRITE);
  429. ERR_CONTINUE_MSG(file.is_null(), vformat("Unable to apply changes to \"%s\", no writing access.", file_name));
  430. file->store_string(file_content_after);
  431. reason.append(vformat(" File was changed, conversion took %d ms.", end_time - start_time));
  432. } else {
  433. reason.append(vformat(" File was left unchanged, checking took %d ms.", end_time - start_time));
  434. }
  435. if (ignored_lines != 0) {
  436. reason.append(vformat(" Ignored %d lines, because their length exceeds maximum allowed characters - %d.", ignored_lines, maximum_line_length));
  437. }
  438. }
  439. for (int k = 0; k < reason.size(); k++) {
  440. print_line(reason[k]);
  441. }
  442. }
  443. 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));
  444. uint64_t conversion_end_time = Time::get_singleton()->get_ticks_msec();
  445. print_line(vformat("Conversion of all files took %10.3f seconds.", (conversion_end_time - conversion_start_time) / 1000.0));
  446. return true;
  447. }
  448. // Function responsible for validating project conversion.
  449. bool ProjectConverter3To4::validate_conversion() {
  450. print_line("Starting checking if project conversion can be done.");
  451. uint64_t conversion_start_time = Time::get_singleton()->get_ticks_msec();
  452. RegExContainer reg_container = RegExContainer();
  453. int cached_maximum_line_length = maximum_line_length;
  454. maximum_line_length = 10000; // To avoid breaking the tests, only use this for the their larger value.
  455. ERR_FAIL_COND_V_MSG(!test_array_names(), false, "Cannot start converting due to problems with data in arrays.");
  456. ERR_FAIL_COND_V_MSG(!test_conversion(reg_container), false, "Aborting conversion due to validation tests failing");
  457. maximum_line_length = cached_maximum_line_length;
  458. // Checking if folder contains valid Godot 3 project.
  459. // Project should not be converted more than once.
  460. {
  461. String conventer_text = "; Project was converted by built-in tool to Godot 4.0";
  462. ERR_FAIL_COND_V_MSG(!FileAccess::exists("project.godot"), false, "Current directory doesn't contain any Godot 3 project");
  463. Error err = OK;
  464. String project_godot_content = FileAccess::get_file_as_string("project.godot", &err);
  465. ERR_FAIL_COND_V_MSG(err != OK, false, "Failed to read content of \"project.godot\" file.");
  466. ERR_FAIL_COND_V_MSG(project_godot_content.contains(conventer_text), false, "Project already was converted with this tool.");
  467. }
  468. Vector<String> collected_files = check_for_files();
  469. uint32_t converted_files = 0;
  470. // Check file by file.
  471. for (int i = 0; i < collected_files.size(); i++) {
  472. String file_name = collected_files[i];
  473. Vector<String> lines;
  474. uint32_t ignored_lines = 0;
  475. uint64_t file_size = 0;
  476. {
  477. Ref<FileAccess> file = FileAccess::open(file_name, FileAccess::READ);
  478. ERR_CONTINUE_MSG(file.is_null(), vformat("Unable to read content of \"%s\".", file_name));
  479. while (!file->eof_reached()) {
  480. String line = file->get_line();
  481. file_size += line.size();
  482. lines.append(line);
  483. }
  484. }
  485. 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));
  486. Vector<String> changed_elements;
  487. Vector<String> reason;
  488. bool is_ignored = false;
  489. uint64_t start_time = Time::get_singleton()->get_ticks_msec();
  490. if (file_name.ends_with(".shader")) {
  491. reason.append("\tFile extension will be renamed from \"shader\" to \"gdshader\".");
  492. }
  493. if (file_size < uint64_t(maximum_file_size)) {
  494. if (file_name.ends_with(".gd")) {
  495. changed_elements.append_array(check_for_rename_classes(lines, reg_container));
  496. changed_elements.append_array(check_for_rename_common(RenamesMap3To4::enum_renames, reg_container.enum_regexes, lines));
  497. changed_elements.append_array(check_for_rename_colors(lines, reg_container));
  498. changed_elements.append_array(check_for_rename_common(RenamesMap3To4::gdscript_function_renames, reg_container.gdscript_function_regexes, lines));
  499. changed_elements.append_array(check_for_rename_gdscript_functions(lines, reg_container, false));
  500. changed_elements.append_array(check_for_rename_common(RenamesMap3To4::project_settings_renames, reg_container.project_settings_regexes, lines));
  501. changed_elements.append_array(check_for_rename_gdscript_keywords(lines, reg_container));
  502. changed_elements.append_array(check_for_rename_common(RenamesMap3To4::gdscript_properties_renames, reg_container.gdscript_properties_regexes, lines));
  503. changed_elements.append_array(check_for_rename_common(RenamesMap3To4::gdscript_signals_renames, reg_container.gdscript_signals_regexes, lines));
  504. changed_elements.append_array(check_for_rename_common(RenamesMap3To4::shaders_renames, reg_container.shaders_regexes, lines));
  505. changed_elements.append_array(check_for_rename_common(RenamesMap3To4::builtin_types_renames, reg_container.builtin_types_regexes, lines));
  506. changed_elements.append_array(check_for_rename_common(RenamesMap3To4::theme_override_renames, reg_container.theme_override_regexes, lines));
  507. changed_elements.append_array(check_for_custom_rename(lines, "\\.shader", ".gdshader"));
  508. } else if (file_name.ends_with(".tscn")) {
  509. changed_elements.append_array(check_for_rename_classes(lines, reg_container));
  510. changed_elements.append_array(check_for_rename_common(RenamesMap3To4::enum_renames, reg_container.enum_regexes, lines));
  511. changed_elements.append_array(check_for_rename_colors(lines, reg_container));
  512. changed_elements.append_array(check_for_rename_common(RenamesMap3To4::gdscript_function_renames, reg_container.gdscript_function_regexes, lines));
  513. changed_elements.append_array(check_for_rename_gdscript_functions(lines, reg_container, true));
  514. changed_elements.append_array(check_for_rename_common(RenamesMap3To4::project_settings_renames, reg_container.project_settings_regexes, lines));
  515. changed_elements.append_array(check_for_rename_gdscript_keywords(lines, reg_container));
  516. changed_elements.append_array(check_for_rename_common(RenamesMap3To4::gdscript_properties_renames, reg_container.gdscript_properties_regexes, lines));
  517. changed_elements.append_array(check_for_rename_common(RenamesMap3To4::gdscript_signals_renames, reg_container.gdscript_signals_regexes, lines));
  518. changed_elements.append_array(check_for_rename_common(RenamesMap3To4::shaders_renames, reg_container.shaders_regexes, lines));
  519. changed_elements.append_array(check_for_rename_common(RenamesMap3To4::builtin_types_renames, reg_container.builtin_types_regexes, lines));
  520. changed_elements.append_array(check_for_rename_common(RenamesMap3To4::theme_override_renames, reg_container.theme_override_regexes, lines));
  521. changed_elements.append_array(check_for_custom_rename(lines, "\\.shader", ".gdshader"));
  522. } else if (file_name.ends_with(".cs")) {
  523. changed_elements.append_array(check_for_rename_classes(lines, reg_container));
  524. changed_elements.append_array(check_for_rename_common(RenamesMap3To4::csharp_function_renames, reg_container.csharp_function_regexes, lines));
  525. changed_elements.append_array(check_for_rename_common(RenamesMap3To4::builtin_types_renames, reg_container.builtin_types_regexes, lines));
  526. changed_elements.append_array(check_for_rename_common(RenamesMap3To4::csharp_properties_renames, reg_container.csharp_properties_regexes, lines));
  527. changed_elements.append_array(check_for_rename_common(RenamesMap3To4::csharp_signals_renames, reg_container.csharp_signal_regexes, lines));
  528. changed_elements.append_array(check_for_rename_csharp_functions(lines, reg_container));
  529. changed_elements.append_array(check_for_rename_csharp_attributes(lines, reg_container));
  530. changed_elements.append_array(check_for_custom_rename(lines, "public class ", "public partial class "));
  531. } else if (file_name.ends_with(".gdshader") || file_name.ends_with(".shader")) {
  532. changed_elements.append_array(check_for_rename_common(RenamesMap3To4::shaders_renames, reg_container.shaders_regexes, lines));
  533. } else if (file_name.ends_with("tres")) {
  534. changed_elements.append_array(check_for_rename_classes(lines, reg_container));
  535. changed_elements.append_array(check_for_rename_common(RenamesMap3To4::shaders_renames, reg_container.shaders_regexes, lines));
  536. changed_elements.append_array(check_for_rename_common(RenamesMap3To4::builtin_types_renames, reg_container.builtin_types_regexes, lines));
  537. changed_elements.append_array(check_for_custom_rename(lines, "\\.shader", ".gdshader"));
  538. } else if (file_name.ends_with("project.godot")) {
  539. changed_elements.append_array(check_for_rename_common(RenamesMap3To4::project_godot_renames, reg_container.project_godot_regexes, lines));
  540. changed_elements.append_array(check_for_rename_common(RenamesMap3To4::builtin_types_renames, reg_container.builtin_types_regexes, lines));
  541. changed_elements.append_array(check_for_rename_input_map_scancode(lines, reg_container));
  542. changed_elements.append_array(check_for_rename_common(RenamesMap3To4::input_map_renames, reg_container.input_map_regexes, lines));
  543. } else if (file_name.ends_with(".csproj")) {
  544. // TODO
  545. } else {
  546. ERR_PRINT(vformat("\"%s\", is not supported!", file_name));
  547. continue;
  548. }
  549. for (String &line : lines) {
  550. if (uint64_t(line.length()) > maximum_line_length) {
  551. ignored_lines += 1;
  552. }
  553. }
  554. } else {
  555. reason.append(vformat("\tERROR: File has exceeded the maximum size allowed - %d KB.", maximum_file_size / 1024));
  556. is_ignored = true;
  557. }
  558. uint64_t end_time = Time::get_singleton()->get_ticks_msec();
  559. String end_message = vformat(" Checking file took %10.3f ms.", (end_time - start_time) / 1000.0);
  560. if (ignored_lines != 0) {
  561. end_message += vformat(" Ignored %d lines, because their length exceeds maximum allowed characters - %d.", ignored_lines, maximum_line_length);
  562. }
  563. print_line(end_message);
  564. for (int k = 0; k < reason.size(); k++) {
  565. print_line(reason[k]);
  566. }
  567. if (changed_elements.size() > 0 && !is_ignored) {
  568. converted_files++;
  569. for (int k = 0; k < changed_elements.size(); k++) {
  570. print_line(String("\t\t") + changed_elements[k]);
  571. }
  572. }
  573. }
  574. 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));
  575. uint64_t conversion_end_time = Time::get_singleton()->get_ticks_msec();
  576. print_line(vformat("Conversion of all files took %10.3f seconds.", (conversion_end_time - conversion_start_time) / 1000.0));
  577. return true;
  578. }
  579. // Collect files which will be checked, excluding ".txt", ".mp4", ".wav" etc. files.
  580. Vector<String> ProjectConverter3To4::check_for_files() {
  581. Vector<String> collected_files = Vector<String>();
  582. Vector<String> directories_to_check = Vector<String>();
  583. directories_to_check.push_back("res://");
  584. while (!directories_to_check.is_empty()) {
  585. String path = directories_to_check.get(directories_to_check.size() - 1); // Is there any pop_back function?
  586. directories_to_check.resize(directories_to_check.size() - 1); // Remove last element
  587. Ref<DirAccess> dir = DirAccess::open(path);
  588. if (dir.is_valid()) {
  589. dir->set_include_hidden(true);
  590. dir->list_dir_begin();
  591. String current_dir = dir->get_current_dir();
  592. String file_name = dir->_get_next();
  593. while (file_name != "") {
  594. if (file_name == ".git" || file_name == ".godot") {
  595. file_name = dir->_get_next();
  596. continue;
  597. }
  598. if (dir->current_is_dir()) {
  599. directories_to_check.append(current_dir.path_join(file_name) + "/");
  600. } else {
  601. bool proper_extension = false;
  602. 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"))
  603. proper_extension = true;
  604. if (proper_extension) {
  605. collected_files.append(current_dir.path_join(file_name));
  606. }
  607. }
  608. file_name = dir->_get_next();
  609. }
  610. } else {
  611. print_verbose("Failed to open " + path);
  612. }
  613. }
  614. return collected_files;
  615. }
  616. Vector<SourceLine> ProjectConverter3To4::split_lines(const String &text) {
  617. Vector<String> lines = text.split("\n");
  618. Vector<SourceLine> source_lines;
  619. for (String &line : lines) {
  620. SourceLine source_line;
  621. source_line.line = line;
  622. source_line.is_comment = false;
  623. source_lines.append(source_line);
  624. }
  625. return source_lines;
  626. }
  627. // Test expected results of gdscript
  628. bool ProjectConverter3To4::test_conversion_gdscript_builtin(String name, String expected, void (ProjectConverter3To4::*func)(Vector<SourceLine> &, const RegExContainer &, bool), String what, const RegExContainer &reg_container, bool builtin_script) {
  629. Vector<SourceLine> got = split_lines(name);
  630. (this->*func)(got, reg_container, builtin_script);
  631. String got_str = collect_string_from_vector(got);
  632. 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));
  633. return true;
  634. }
  635. bool ProjectConverter3To4::test_conversion_with_regex(String name, String expected, void (ProjectConverter3To4::*func)(Vector<SourceLine> &, const RegExContainer &), String what, const RegExContainer &reg_container) {
  636. Vector<SourceLine> got = split_lines(name);
  637. (this->*func)(got, reg_container);
  638. String got_str = collect_string_from_vector(got);
  639. 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));
  640. return true;
  641. }
  642. bool ProjectConverter3To4::test_conversion_basic(String name, String expected, const char *array[][2], LocalVector<RegEx *> &regex_cache, String what) {
  643. Vector<SourceLine> got = split_lines(name);
  644. rename_common(array, regex_cache, got);
  645. String got_str = collect_string_from_vector(got);
  646. 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));
  647. return true;
  648. }
  649. // Validate if conversions are proper.
  650. bool ProjectConverter3To4::test_conversion(RegExContainer &reg_container) {
  651. bool valid = true;
  652. valid = valid && test_conversion_with_regex("tool", "@tool", &ProjectConverter3To4::fix_tool_declaration, "gdscript keyword", reg_container);
  653. valid = valid && test_conversion_with_regex("\n tool", "\n tool", &ProjectConverter3To4::fix_tool_declaration, "gdscript keyword", reg_container);
  654. valid = valid && test_conversion_with_regex("\n\ntool", "@tool\n\n", &ProjectConverter3To4::fix_tool_declaration, "gdscript keyword", reg_container);
  655. valid = valid && test_conversion_basic("TYPE_REAL", "TYPE_FLOAT", RenamesMap3To4::enum_renames, reg_container.enum_regexes, "enum");
  656. valid = valid && test_conversion_basic("can_instance", "can_instantiate", RenamesMap3To4::gdscript_function_renames, reg_container.gdscript_function_regexes, "gdscript function");
  657. valid = valid && test_conversion_basic("CanInstance", "CanInstantiate", RenamesMap3To4::csharp_function_renames, reg_container.csharp_function_regexes, "csharp function");
  658. valid = valid && test_conversion_basic("translation", "position", RenamesMap3To4::gdscript_properties_renames, reg_container.gdscript_properties_regexes, "gdscript property");
  659. valid = valid && test_conversion_basic("Translation", "Position", RenamesMap3To4::csharp_properties_renames, reg_container.csharp_properties_regexes, "csharp property");
  660. valid = valid && test_conversion_basic("NORMALMAP", "NORMAL_MAP", RenamesMap3To4::shaders_renames, reg_container.shaders_regexes, "shader");
  661. valid = valid && test_conversion_basic("text_entered", "text_submitted", RenamesMap3To4::gdscript_signals_renames, reg_container.gdscript_signals_regexes, "gdscript signal");
  662. valid = valid && test_conversion_basic("TextEntered", "TextSubmitted", RenamesMap3To4::csharp_signals_renames, reg_container.csharp_signal_regexes, "csharp signal");
  663. 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");
  664. 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");
  665. valid = valid && test_conversion_basic("Transform", "Transform3D", RenamesMap3To4::builtin_types_renames, reg_container.builtin_types_regexes, "builtin type");
  666. 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");
  667. // Custom Renames.
  668. 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);
  669. 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);
  670. 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);
  671. valid = valid && test_conversion_with_regex("[Remote]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container);
  672. valid = valid && test_conversion_with_regex("[RemoteSync]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container);
  673. valid = valid && test_conversion_with_regex("[Sync]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container);
  674. valid = valid && test_conversion_with_regex("[Slave]", "[RPC]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container);
  675. valid = valid && test_conversion_with_regex("[Puppet]", "[RPC]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container);
  676. valid = valid && test_conversion_with_regex("[PuppetSync]", "[RPC(CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container);
  677. 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);
  678. 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);
  679. 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);
  680. 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);
  681. 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);
  682. 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);
  683. 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);
  684. 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);
  685. 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);
  686. 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);
  687. 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);
  688. 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);
  689. 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);
  690. 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);
  691. 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);
  692. 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);
  693. 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);
  694. 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);
  695. 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);
  696. 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);
  697. 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);
  698. 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);
  699. 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);
  700. 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);
  701. 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);
  702. 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);
  703. 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);
  704. 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);
  705. 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);
  706. 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);
  707. 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# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tr.move_and_slide()\n\tvar aa = roman(r.velocity) # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
  708. 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# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tmove_and_slide() # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
  709. 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# TODOConverter40 looks that snap in Godot 4.0 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# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tr.move_and_slide()\n\tvar aa = roman(r.velocity) # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
  710. valid = valid && test_conversion_gdscript_builtin("\tmove_and_slide_with_snap( a, g, b, c, d, e, f ) # Roman", "\tset_velocity(a)\n\t# TODOConverter40 looks that snap in Godot 4.0 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# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tmove_and_slide() # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
  711. valid = valid && test_conversion_gdscript_builtin("list_dir_begin( a , b )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
  712. valid = valid && test_conversion_gdscript_builtin("list_dir_begin( a )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
  713. valid = valid && test_conversion_gdscript_builtin("list_dir_begin( )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
  714. valid = valid && test_conversion_gdscript_builtin("sort_custom( a , b )", "sort_custom(Callable(a, b))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
  715. 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);
  716. 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);
  717. valid = valid && test_conversion_gdscript_builtin("\timage.lock()", "\tfalse # image.lock() # TODOConverter40, 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);
  718. valid = valid && test_conversion_gdscript_builtin("\timage.unlock()", "\tfalse # image.unlock() # TODOConverter40, 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);
  719. valid = valid && test_conversion_gdscript_builtin("\troman.image.unlock()", "\tfalse # roman.image.unlock() # TODOConverter40, 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);
  720. valid = valid && test_conversion_gdscript_builtin("\tmtx.lock()", "\tmtx.lock()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
  721. valid = valid && test_conversion_gdscript_builtin("\tmutex.unlock()", "\tmutex.unlock()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
  722. valid = valid && test_conversion_with_regex("extends CSGBox", "extends CSGBox3D", &ProjectConverter3To4::rename_classes, "classes", reg_container);
  723. valid = valid && test_conversion_with_regex("CSGBox", "CSGBox3D", &ProjectConverter3To4::rename_classes, "classes", reg_container);
  724. valid = valid && test_conversion_with_regex("Spatial", "Node3D", &ProjectConverter3To4::rename_classes, "classes", reg_container);
  725. valid = valid && test_conversion_with_regex("Spatial.tscn", "Spatial.tscn", &ProjectConverter3To4::rename_classes, "classes", reg_container);
  726. valid = valid && test_conversion_with_regex("Spatial.gd", "Spatial.gd", &ProjectConverter3To4::rename_classes, "classes", reg_container);
  727. valid = valid && test_conversion_with_regex("Spatial.shader", "Spatial.shader", &ProjectConverter3To4::rename_classes, "classes", reg_container);
  728. valid = valid && test_conversion_with_regex("Spatial.other", "Node3D.other", &ProjectConverter3To4::rename_classes, "classes", reg_container);
  729. valid = valid && test_conversion_with_regex("\nonready", "\n@onready", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
  730. valid = valid && test_conversion_with_regex("onready", "@onready", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
  731. valid = valid && test_conversion_with_regex(" onready", " onready", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
  732. valid = valid && test_conversion_with_regex("\nexport", "\n@export", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
  733. valid = valid && test_conversion_with_regex("\texport", "\t@export", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
  734. valid = valid && test_conversion_with_regex("\texport_dialog", "\texport_dialog", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
  735. valid = valid && test_conversion_with_regex("export", "@export", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
  736. valid = valid && test_conversion_with_regex(" export", " export", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
  737. valid = valid && test_conversion_with_regex("\n\nremote func", "\n\n@rpc(\"any_peer\") func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
  738. valid = valid && test_conversion_with_regex("\n\nremotesync func", "\n\n@rpc(\"any_peer\", \"call_local\") func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
  739. valid = valid && test_conversion_with_regex("\n\nsync func", "\n\n@rpc(\"any_peer\", \"call_local\") func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
  740. valid = valid && test_conversion_with_regex("\n\nslave func", "\n\n@rpc func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
  741. valid = valid && test_conversion_with_regex("\n\npuppet func", "\n\n@rpc func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
  742. valid = valid && test_conversion_with_regex("\n\npuppetsync func", "\n\n@rpc(\"call_local\") func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
  743. valid = valid && test_conversion_with_regex("\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);
  744. valid = valid && test_conversion_with_regex("\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);
  745. 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);
  746. 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);
  747. 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);
  748. 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);
  749. valid = valid && test_conversion_gdscript_builtin("get_node(@", "get_node(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
  750. valid = valid && test_conversion_gdscript_builtin("yield(this, \"timeout\")", "await this.timeout", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
  751. valid = valid && test_conversion_gdscript_builtin("yield(this, \\\"timeout\\\")", "await this.timeout", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, true);
  752. 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);
  753. 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);
  754. 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);
  755. 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
  756. 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);
  757. 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);
  758. valid = valid && test_conversion_gdscript_builtin("to_json( AA ) szon", "JSON.new().stringify( AA ) szon", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
  759. valid = valid && test_conversion_gdscript_builtin("s to_json", "s JSON.new().stringify", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
  760. valid = valid && test_conversion_gdscript_builtin("AF to_json2", "AF to_json2", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
  761. 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);
  762. valid = valid && test_conversion_gdscript_builtin("empty()", "is_empty()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
  763. valid = valid && test_conversion_gdscript_builtin(".empty", ".empty", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
  764. valid = valid && test_conversion_gdscript_builtin(").roman(", ").roman(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
  765. valid = valid && test_conversion_gdscript_builtin("\t.roman(", "\tsuper.roman(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
  766. valid = valid && test_conversion_gdscript_builtin(" .roman(", " super.roman(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
  767. valid = valid && test_conversion_gdscript_builtin(".1", ".1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
  768. valid = valid && test_conversion_gdscript_builtin(" .1", " .1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
  769. valid = valid && test_conversion_gdscript_builtin("'.'", "'.'", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
  770. valid = valid && test_conversion_gdscript_builtin("'.a'", "'.a'", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
  771. valid = valid && test_conversion_gdscript_builtin("\t._input(_event)", "\tsuper._input(_event)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
  772. 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);
  773. 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);
  774. 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);
  775. 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);
  776. 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);
  777. 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);
  778. valid = valid && test_conversion_gdscript_builtin("(start(A,B) != OK):", "(start(Callable(A, B)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
  779. valid = valid && test_conversion_gdscript_builtin("func start(A,B):", "func start(A,B):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
  780. 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);
  781. 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);
  782. 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);
  783. 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);
  784. 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);
  785. 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);
  786. 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);
  787. 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);
  788. valid = valid && test_conversion_gdscript_builtin("func _init(", "func _init(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
  789. 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);
  790. 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);
  791. 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);
  792. 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);
  793. 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);
  794. valid = valid && test_conversion_gdscript_builtin("assert(speed < 20, str(randi()%10))", "assert(speed < 20) #,str(randi()%10))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
  795. valid = valid && test_conversion_gdscript_builtin("assert(speed < 2)", "assert(speed < 2)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
  796. valid = valid && test_conversion_gdscript_builtin("assert(false, \"Missing type --\" + str(argument.type) + \"--, needs to be added to project\")", "assert(false) #,\"Missing type --\" + str(argument.type) + \"--, needs to be added to project\")", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
  797. 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);
  798. 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);
  799. 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);
  800. 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);
  801. 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);
  802. 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);
  803. 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);
  804. valid = valid && test_conversion_gdscript_builtin("PackedStringArray(req_godot).join('.')", "'.'.join(PackedStringArray(req_godot))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
  805. valid = valid && test_conversion_gdscript_builtin("=PackedStringArray(req_godot).join('.')", "='.'.join(PackedStringArray(req_godot))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
  806. valid = valid && test_conversion_gdscript_builtin("apply_force(position, impulse)", "apply_force(impulse, position)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
  807. valid = valid && test_conversion_gdscript_builtin("apply_impulse(position, impulse)", "apply_impulse(impulse, position)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
  808. valid = valid && test_conversion_gdscript_builtin("draw_rect(a,b,c,d,e).abc", "draw_rect(a, b, c, d).abc# e) TODOGODOT4 Antialiasing argument is missing", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
  809. valid = valid && test_conversion_gdscript_builtin("get_focus_owner()", "get_viewport().gui_get_focus_owner()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
  810. valid = valid && test_conversion_gdscript_builtin("button.pressed = 1", "button.button_pressed = 1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
  811. valid = valid && test_conversion_gdscript_builtin("button.pressed=1", "button.button_pressed=1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
  812. valid = valid && test_conversion_gdscript_builtin("button.pressed SF", "button.pressed SF", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
  813. valid = valid && test_conversion_with_regex("AAA Color.white AF", "AAA Color.WHITE AF", &ProjectConverter3To4::rename_colors, "custom rename", reg_container);
  814. // Note: Do not change to *scancode*, it is applied before that conversion.
  815. 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);
  816. 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);
  817. // Custom rule conversion
  818. {
  819. String from = "instance";
  820. String to = "instantiate";
  821. String name = "AA.instance()";
  822. Vector<SourceLine> got = split_lines(name);
  823. String expected = "AA.instantiate()";
  824. custom_rename(got, from, to);
  825. String got_str = collect_string_from_vector(got);
  826. if (got_str != expected) {
  827. ERR_PRINT(vformat("Failed to convert custom rename \"%s\" to \"%s\", got \"%s\", instead.", name, expected, got_str));
  828. }
  829. valid = valid && (got_str == expected);
  830. }
  831. // get_object_of_execution
  832. {
  833. { String base = "var roman = kieliszek.";
  834. String expected = "kieliszek.";
  835. String got = get_object_of_execution(base);
  836. if (got != expected) {
  837. 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()));
  838. }
  839. valid = valid && (got == expected);
  840. }
  841. {
  842. String base = "r.";
  843. String expected = "r.";
  844. String got = get_object_of_execution(base);
  845. if (got != expected) {
  846. 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()));
  847. }
  848. valid = valid && (got == expected);
  849. }
  850. {
  851. String base = "mortadela(";
  852. String expected = "";
  853. String got = get_object_of_execution(base);
  854. if (got != expected) {
  855. 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()));
  856. }
  857. valid = valid && (got == expected);
  858. }
  859. {
  860. String base = "var node = $world/ukraine/lviv.";
  861. String expected = "$world/ukraine/lviv.";
  862. String got = get_object_of_execution(base);
  863. if (got != expected) {
  864. 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()));
  865. }
  866. valid = valid && (got == expected);
  867. }
  868. }
  869. // get_starting_space
  870. {
  871. String base = "\t\t\t var roman = kieliszek.";
  872. String expected = "\t\t\t";
  873. String got = get_starting_space(base);
  874. if (got != expected) {
  875. 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()));
  876. }
  877. valid = valid && (got == expected);
  878. }
  879. // Parse Arguments
  880. {
  881. String line = "( )";
  882. Vector<String> got_vector = parse_arguments(line);
  883. String got = "";
  884. String expected = "";
  885. for (String &part : got_vector) {
  886. got += part + "|||";
  887. }
  888. if (got != expected) {
  889. 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()));
  890. }
  891. valid = valid && (got == expected);
  892. }
  893. {
  894. String line = "(a , b , c)";
  895. Vector<String> got_vector = parse_arguments(line);
  896. String got = "";
  897. String expected = "a|||b|||c|||";
  898. for (String &part : got_vector) {
  899. got += part + "|||";
  900. }
  901. if (got != expected) {
  902. 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()));
  903. }
  904. valid = valid && (got == expected);
  905. }
  906. {
  907. String line = "(a , \"b,\" , c)";
  908. Vector<String> got_vector = parse_arguments(line);
  909. String got = "";
  910. String expected = "a|||\"b,\"|||c|||";
  911. for (String &part : got_vector) {
  912. got += part + "|||";
  913. }
  914. if (got != expected) {
  915. 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()));
  916. }
  917. valid = valid && (got == expected);
  918. }
  919. {
  920. String line = "(a , \"(,),,,,\" , c)";
  921. Vector<String> got_vector = parse_arguments(line);
  922. String got = "";
  923. String expected = "a|||\"(,),,,,\"|||c|||";
  924. for (String &part : got_vector) {
  925. got += part + "|||";
  926. }
  927. if (got != expected) {
  928. 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()));
  929. }
  930. valid = valid && (got == expected);
  931. }
  932. return valid;
  933. }
  934. // Validate in all arrays if names don't do cyclic renames "Node" -> "Node2D" | "Node2D" -> "2DNode"
  935. bool ProjectConverter3To4::test_array_names() {
  936. bool valid = true;
  937. Vector<String> names = Vector<String>();
  938. // Validate if all classes are valid.
  939. {
  940. for (unsigned int current_index = 0; RenamesMap3To4::class_renames[current_index][0]; current_index++) {
  941. const String old_class = RenamesMap3To4::class_renames[current_index][0];
  942. const String new_class = RenamesMap3To4::class_renames[current_index][1];
  943. // Light2D, Texture, Viewport are special classes(probably virtual ones).
  944. if (ClassDB::class_exists(StringName(old_class)) && old_class != "Light2D" && old_class != "Texture" && old_class != "Viewport") {
  945. ERR_PRINT(vformat("Class \"%s\" exists in Godot 4.0, so it cannot be renamed to something else.", old_class));
  946. valid = false; // This probably should be only a warning, but not 100% sure - this would need to be added to CI.
  947. }
  948. // Callable is special class, to which normal classes may be renamed.
  949. if (!ClassDB::class_exists(StringName(new_class)) && new_class != "Callable") {
  950. ERR_PRINT(vformat("Class \"%s\" does not exist in Godot 4.0, so it cannot be used in the conversion.", old_class));
  951. valid = false; // This probably should be only a warning, but not 100% sure - this would need to be added to CI.
  952. }
  953. }
  954. }
  955. {
  956. HashSet<String> all_functions;
  957. // List of excluded functions from builtin types and global namespace, because currently it is not possible to get list of functions from them.
  958. // This will be available when https://github.com/godotengine/godot/pull/49053 or similar will be included into Godot.
  959. 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", "snapped", "remap", "rfind", nullptr };
  960. for (int current_index = 0; builtin_types_excluded_functions[current_index]; current_index++) {
  961. all_functions.insert(builtin_types_excluded_functions[current_index]);
  962. }
  963. //for (int type = Variant::Type::NIL + 1; type < Variant::Type::VARIANT_MAX; type++) {
  964. // List<MethodInfo> method_list;
  965. // Variant::get_method_list_by_type(&method_list, Variant::Type(type));
  966. // for (MethodInfo &function_data : method_list) {
  967. // if (!all_functions.has(function_data.name)) {
  968. // all_functions.insert(function_data.name);
  969. // }
  970. // }
  971. //}
  972. List<StringName> classes_list;
  973. ClassDB::get_class_list(&classes_list);
  974. for (StringName &name_of_class : classes_list) {
  975. List<MethodInfo> method_list;
  976. ClassDB::get_method_list(name_of_class, &method_list, true);
  977. for (MethodInfo &function_data : method_list) {
  978. if (!all_functions.has(function_data.name)) {
  979. all_functions.insert(function_data.name);
  980. }
  981. }
  982. }
  983. int current_element = 0;
  984. while (RenamesMap3To4::gdscript_function_renames[current_element][0] != nullptr) {
  985. String name_3_x = RenamesMap3To4::gdscript_function_renames[current_element][0];
  986. String name_4_0 = RenamesMap3To4::gdscript_function_renames[current_element][1];
  987. if (!all_functions.has(name_4_0)) {
  988. ERR_PRINT(vformat("Missing GDScript function in pair (%s - ===> %s <===)", name_3_x, name_4_0));
  989. valid = false;
  990. }
  991. current_element++;
  992. }
  993. }
  994. if (!valid) {
  995. 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.");
  996. }
  997. valid = valid && test_single_array(RenamesMap3To4::enum_renames);
  998. valid = valid && test_single_array(RenamesMap3To4::class_renames, true);
  999. valid = valid && test_single_array(RenamesMap3To4::gdscript_function_renames, true);
  1000. valid = valid && test_single_array(RenamesMap3To4::csharp_function_renames, true);
  1001. valid = valid && test_single_array(RenamesMap3To4::gdscript_properties_renames, true);
  1002. valid = valid && test_single_array(RenamesMap3To4::csharp_properties_renames, true);
  1003. valid = valid && test_single_array(RenamesMap3To4::shaders_renames, true);
  1004. valid = valid && test_single_array(RenamesMap3To4::gdscript_signals_renames);
  1005. valid = valid && test_single_array(RenamesMap3To4::project_settings_renames);
  1006. valid = valid && test_single_array(RenamesMap3To4::project_godot_renames);
  1007. valid = valid && test_single_array(RenamesMap3To4::input_map_renames);
  1008. valid = valid && test_single_array(RenamesMap3To4::builtin_types_renames);
  1009. valid = valid && test_single_array(RenamesMap3To4::color_renames);
  1010. return valid;
  1011. }
  1012. // Validates the array to prevent cyclic renames, such as `Node` -> `Node2D`, then `Node2D` -> `2DNode`.
  1013. // Also checks if names contain leading or trailing spaces.
  1014. bool ProjectConverter3To4::test_single_array(const char *p_array[][2], bool p_ignore_4_0_name) {
  1015. bool valid = true;
  1016. Vector<String> names = Vector<String>();
  1017. for (unsigned int current_index = 0; p_array[current_index][0]; current_index++) {
  1018. String name_3_x = p_array[current_index][0];
  1019. String name_4_0 = p_array[current_index][1];
  1020. if (name_3_x != name_3_x.strip_edges()) {
  1021. ERR_PRINT(vformat("Invalid Entry \"%s\" contains leading or trailing spaces.", name_3_x));
  1022. valid = false;
  1023. }
  1024. if (names.has(name_3_x)) {
  1025. ERR_PRINT(vformat("Found duplicated entry, pair ( -> %s , %s)", name_3_x, name_4_0));
  1026. valid = false;
  1027. }
  1028. names.append(name_3_x);
  1029. if (name_4_0 != name_4_0.strip_edges()) {
  1030. ERR_PRINT(vformat("Invalid Entry \"%s\" contains leading or trailing spaces.", name_3_x));
  1031. valid = false;
  1032. }
  1033. if (names.has(name_4_0)) {
  1034. ERR_PRINT(vformat("Found duplicated entry, pair ( -> %s , %s)", name_3_x, name_4_0));
  1035. valid = false;
  1036. }
  1037. if (!p_ignore_4_0_name) {
  1038. names.append(name_4_0);
  1039. }
  1040. }
  1041. return valid;
  1042. };
  1043. // Returns arguments from given function execution, this cannot be really done as regex.
  1044. // `abc(d,e(f,g),h)` -> [d], [e(f,g)], [h]
  1045. Vector<String> ProjectConverter3To4::parse_arguments(const String &line) {
  1046. Vector<String> parts;
  1047. int string_size = line.length();
  1048. int start_part = 0; // Index of beginning of start part.
  1049. int parts_counter = 0;
  1050. char32_t previous_character = '\0';
  1051. bool is_inside_string = false; // If true, it ignores these 3 characters ( , ) inside string.
  1052. 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));
  1053. for (int current_index = 0; current_index < string_size; current_index++) {
  1054. char32_t character = line.get(current_index);
  1055. switch (character) {
  1056. case '(': {
  1057. parts_counter++;
  1058. if (parts_counter == 1 && !is_inside_string) {
  1059. start_part = current_index;
  1060. }
  1061. break;
  1062. };
  1063. case ')': {
  1064. parts_counter--;
  1065. if (parts_counter == 0 && !is_inside_string) {
  1066. parts.append(line.substr(start_part + 1, current_index - start_part - 1));
  1067. start_part = current_index;
  1068. }
  1069. break;
  1070. };
  1071. case '[': {
  1072. parts_counter++;
  1073. if (parts_counter == 1 && !is_inside_string) {
  1074. start_part = current_index;
  1075. }
  1076. break;
  1077. };
  1078. case ']': {
  1079. parts_counter--;
  1080. if (parts_counter == 0 && !is_inside_string) {
  1081. parts.append(line.substr(start_part, current_index - start_part));
  1082. start_part = current_index;
  1083. }
  1084. break;
  1085. };
  1086. case ',': {
  1087. if (parts_counter == 1 && !is_inside_string) {
  1088. parts.append(line.substr(start_part + 1, current_index - start_part - 1));
  1089. start_part = current_index;
  1090. }
  1091. break;
  1092. };
  1093. case '"': {
  1094. if (previous_character != '\\')
  1095. is_inside_string = !is_inside_string;
  1096. }
  1097. }
  1098. previous_character = character;
  1099. }
  1100. Vector<String> clean_parts;
  1101. for (String &part : parts) {
  1102. part = part.strip_edges();
  1103. if (!part.is_empty()) {
  1104. clean_parts.append(part);
  1105. }
  1106. }
  1107. return clean_parts;
  1108. }
  1109. // Finds latest parenthesis owned by function.
  1110. // `function(abc(a,b),DD)):` finds this parenthess `function(abc(a,b),DD => ) <= ):`
  1111. int ProjectConverter3To4::get_end_parenthesis(const String &line) const {
  1112. int current_state = 0;
  1113. for (int current_index = 0; line.length() > current_index; current_index++) {
  1114. char32_t character = line.get(current_index);
  1115. if (character == '(') {
  1116. current_state++;
  1117. }
  1118. if (character == ')') {
  1119. current_state--;
  1120. if (current_state == 0) {
  1121. return current_index;
  1122. }
  1123. }
  1124. }
  1125. return -1;
  1126. }
  1127. // Merges multiple arguments into a single String.
  1128. // Needed when after processing e.g. 2 arguments, later arguments are not changed in any way.
  1129. String ProjectConverter3To4::connect_arguments(const Vector<String> &arguments, int from, int to) const {
  1130. if (to == -1) {
  1131. to = arguments.size();
  1132. }
  1133. String value;
  1134. if (arguments.size() > 0 && from != 0 && from < to) {
  1135. value = ", ";
  1136. }
  1137. for (int i = from; i < to; i++) {
  1138. value += arguments[i];
  1139. if (i != to - 1) {
  1140. value += ", ";
  1141. }
  1142. }
  1143. return value;
  1144. }
  1145. // Returns the indentation (spaces and tabs) at the start of the line e.g. `\t\tmove_this` returns `\t\t`.
  1146. String ProjectConverter3To4::get_starting_space(const String &line) const {
  1147. String empty_space;
  1148. int current_character = 0;
  1149. if (line.is_empty()) {
  1150. return empty_space;
  1151. }
  1152. if (line[0] == ' ') {
  1153. while (current_character < line.size()) {
  1154. if (line[current_character] == ' ') {
  1155. empty_space += ' ';
  1156. current_character++;
  1157. } else {
  1158. break;
  1159. }
  1160. }
  1161. }
  1162. if (line[0] == '\t') {
  1163. while (current_character < line.size()) {
  1164. if (line[current_character] == '\t') {
  1165. empty_space += '\t';
  1166. current_character++;
  1167. } else {
  1168. break;
  1169. }
  1170. }
  1171. }
  1172. return empty_space;
  1173. }
  1174. // Returns the object that’s executing the function in the line.
  1175. // e.g. Passing the line "var roman = kieliszek.funkcja()" to this function returns "kieliszek".
  1176. String ProjectConverter3To4::get_object_of_execution(const String &line) const {
  1177. int end = line.size() - 1; // Last one is \0
  1178. int variable_start = end - 1;
  1179. int start = end - 1;
  1180. bool is_possibly_nodepath = false;
  1181. bool is_valid_nodepath = false;
  1182. while (start >= 0) {
  1183. char32_t character = line[start];
  1184. bool is_variable_char = (character >= 'A' && character <= 'Z') || (character >= 'a' && character <= 'z') || character == '.' || character == '_';
  1185. bool is_nodepath_start = character == '$';
  1186. bool is_nodepath_sep = character == '/';
  1187. if (is_variable_char || is_nodepath_start || is_nodepath_sep) {
  1188. if (start == 0) {
  1189. break;
  1190. } else if (is_nodepath_sep) {
  1191. // Freeze variable_start, try to fetch more chars since this might be a Node path literal.
  1192. is_possibly_nodepath = true;
  1193. } else if (is_nodepath_start) {
  1194. // Found $, this is a Node path literal.
  1195. is_valid_nodepath = true;
  1196. break;
  1197. }
  1198. if (!is_possibly_nodepath) {
  1199. variable_start--;
  1200. }
  1201. start--;
  1202. continue;
  1203. } else {
  1204. // Abandon all hope, this is neither a variable nor a Node path literal.
  1205. variable_start++; // Found invalid character, needs to be ignored.
  1206. break;
  1207. }
  1208. }
  1209. if (is_valid_nodepath) {
  1210. variable_start = start;
  1211. }
  1212. return line.substr(variable_start, (end - variable_start));
  1213. }
  1214. void ProjectConverter3To4::rename_colors(Vector<SourceLine> &source_lines, const RegExContainer &reg_container) {
  1215. for (SourceLine &source_line : source_lines) {
  1216. if (source_line.is_comment) {
  1217. continue;
  1218. }
  1219. String &line = source_line.line;
  1220. if (uint64_t(line.length()) <= maximum_line_length) {
  1221. if (line.contains("Color.")) {
  1222. for (unsigned int current_index = 0; RenamesMap3To4::color_renames[current_index][0]; current_index++) {
  1223. line = reg_container.color_regexes[current_index]->sub(line, reg_container.color_renamed[current_index], true);
  1224. }
  1225. }
  1226. }
  1227. }
  1228. };
  1229. Vector<String> ProjectConverter3To4::check_for_rename_colors(Vector<String> &lines, const RegExContainer &reg_container) {
  1230. Vector<String> found_renames;
  1231. int current_line = 1;
  1232. for (String &line : lines) {
  1233. if (uint64_t(line.length()) <= maximum_line_length) {
  1234. if (line.contains("Color.")) {
  1235. for (unsigned int current_index = 0; RenamesMap3To4::color_renames[current_index][0]; current_index++) {
  1236. TypedArray<RegExMatch> reg_match = reg_container.color_regexes[current_index]->search_all(line);
  1237. if (reg_match.size() > 0) {
  1238. found_renames.append(line_formatter(current_line, RenamesMap3To4::color_renames[current_index][0], RenamesMap3To4::color_renames[current_index][1], line));
  1239. }
  1240. }
  1241. }
  1242. }
  1243. current_line++;
  1244. }
  1245. return found_renames;
  1246. }
  1247. void ProjectConverter3To4::fix_tool_declaration(Vector<SourceLine> &source_lines, const RegExContainer &reg_container) {
  1248. // In godot4, "tool" became "@tool" and must be located at the top of the file
  1249. for (int i = 0; i < source_lines.size(); ++i) {
  1250. if (source_lines[i].line == "tool") {
  1251. source_lines.remove_at(i);
  1252. source_lines.insert(0, { "@tool", false });
  1253. return; // assuming there's at most 1 tool declaration
  1254. }
  1255. }
  1256. }
  1257. void ProjectConverter3To4::rename_classes(Vector<SourceLine> &source_lines, const RegExContainer &reg_container) {
  1258. for (SourceLine &source_line : source_lines) {
  1259. if (source_line.is_comment) {
  1260. continue;
  1261. }
  1262. String &line = source_line.line;
  1263. if (uint64_t(line.length()) <= maximum_line_length) {
  1264. for (unsigned int current_index = 0; RenamesMap3To4::class_renames[current_index][0]; current_index++) {
  1265. if (line.contains(RenamesMap3To4::class_renames[current_index][0])) {
  1266. bool found_ignored_items = false;
  1267. // Renaming Spatial.tscn to TEMP_RENAMED_CLASS.tscn.
  1268. if (line.contains(String(RenamesMap3To4::class_renames[current_index][0]) + ".")) {
  1269. found_ignored_items = true;
  1270. line = reg_container.class_tscn_regexes[current_index]->sub(line, "TEMP_RENAMED_CLASS.tscn", true);
  1271. line = reg_container.class_gd_regexes[current_index]->sub(line, "TEMP_RENAMED_CLASS.gd", true);
  1272. line = reg_container.class_shader_regexes[current_index]->sub(line, "TEMP_RENAMED_CLASS.shader", true);
  1273. }
  1274. // Causal renaming Spatial -> Node3D.
  1275. line = reg_container.class_regexes[current_index]->sub(line, RenamesMap3To4::class_renames[current_index][1], true);
  1276. // Restore Spatial.tscn from TEMP_RENAMED_CLASS.tscn.
  1277. if (found_ignored_items) {
  1278. line = reg_container.class_temp_tscn.sub(line, reg_container.class_temp_tscn_renames[current_index], true);
  1279. line = reg_container.class_temp_gd.sub(line, reg_container.class_temp_gd_renames[current_index], true);
  1280. line = reg_container.class_temp_shader.sub(line, reg_container.class_temp_shader_renames[current_index], true);
  1281. }
  1282. }
  1283. }
  1284. }
  1285. }
  1286. };
  1287. Vector<String> ProjectConverter3To4::check_for_rename_classes(Vector<String> &lines, const RegExContainer &reg_container) {
  1288. Vector<String> found_renames;
  1289. int current_line = 1;
  1290. for (String &line : lines) {
  1291. if (uint64_t(line.length()) <= maximum_line_length) {
  1292. for (unsigned int current_index = 0; RenamesMap3To4::class_renames[current_index][0]; current_index++) {
  1293. if (line.contains(RenamesMap3To4::class_renames[current_index][0])) {
  1294. String old_line = line;
  1295. bool found_ignored_items = false;
  1296. // Renaming Spatial.tscn to TEMP_RENAMED_CLASS.tscn.
  1297. if (line.contains(String(RenamesMap3To4::class_renames[current_index][0]) + ".")) {
  1298. found_ignored_items = true;
  1299. line = reg_container.class_tscn_regexes[current_index]->sub(line, "TEMP_RENAMED_CLASS.tscn", true);
  1300. line = reg_container.class_gd_regexes[current_index]->sub(line, "TEMP_RENAMED_CLASS.gd", true);
  1301. line = reg_container.class_shader_regexes[current_index]->sub(line, "TEMP_RENAMED_CLASS.shader", true);
  1302. }
  1303. // Causal renaming Spatial -> Node3D.
  1304. TypedArray<RegExMatch> reg_match = reg_container.class_regexes[current_index]->search_all(line);
  1305. if (reg_match.size() > 0) {
  1306. found_renames.append(line_formatter(current_line, RenamesMap3To4::class_renames[current_index][0], RenamesMap3To4::class_renames[current_index][1], old_line));
  1307. }
  1308. // Restore Spatial.tscn from TEMP_RENAMED_CLASS.tscn.
  1309. if (found_ignored_items) {
  1310. line = reg_container.class_temp_tscn.sub(line, reg_container.class_temp_tscn_renames[current_index], true);
  1311. line = reg_container.class_temp_gd.sub(line, reg_container.class_temp_gd_renames[current_index], true);
  1312. line = reg_container.class_temp_shader.sub(line, reg_container.class_temp_shader_renames[current_index], true);
  1313. }
  1314. }
  1315. }
  1316. }
  1317. current_line++;
  1318. }
  1319. return found_renames;
  1320. }
  1321. void ProjectConverter3To4::rename_gdscript_functions(Vector<SourceLine> &source_lines, const RegExContainer &reg_container, bool builtin) {
  1322. for (SourceLine &source_line : source_lines) {
  1323. if (source_line.is_comment) {
  1324. continue;
  1325. }
  1326. String &line = source_line.line;
  1327. if (uint64_t(line.length()) <= maximum_line_length) {
  1328. process_gdscript_line(line, reg_container, builtin);
  1329. }
  1330. }
  1331. };
  1332. Vector<String> ProjectConverter3To4::check_for_rename_gdscript_functions(Vector<String> &lines, const RegExContainer &reg_container, bool builtin) {
  1333. int current_line = 1;
  1334. Vector<String> found_renames;
  1335. for (String &line : lines) {
  1336. if (uint64_t(line.length()) <= maximum_line_length) {
  1337. String old_line = line;
  1338. process_gdscript_line(line, reg_container, builtin);
  1339. if (old_line != line) {
  1340. found_renames.append(simple_line_formatter(current_line, old_line, line));
  1341. }
  1342. }
  1343. }
  1344. return found_renames;
  1345. }
  1346. // TODO, this function should run only on all ".gd" files and also on lines in ".tscn" files which are parts of built-in Scripts.
  1347. void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContainer &reg_container, bool builtin) {
  1348. // In this and other functions, reg.sub() is used only after checking lines with str.contains().
  1349. // With longer lines, doing so can sometimes be significantly faster.
  1350. if ((line.contains(".lock") || line.contains(".unlock")) && !line.contains("mtx") && !line.contains("mutex") && !line.contains("Mutex")) {
  1351. line = reg_container.reg_image_lock.sub(line, "false # $1.lock() # TODOConverter40, Image no longer requires locking, `false` helps to not break one line if/else, so it can freely be removed", true);
  1352. line = reg_container.reg_image_unlock.sub(line, "false # $1.unlock() # TODOConverter40, Image no longer requires locking, `false` helps to not break one line if/else, so it can freely be removed", true);
  1353. }
  1354. // PackedStringArray(req_godot).join('.') -> '.'.join(PackedStringArray(req_godot)) PoolStringArray
  1355. if (line.contains(".join")) {
  1356. line = reg_container.reg_join.sub(line, "$2.join($1)", true);
  1357. }
  1358. // -- empty() -> is_empty() Pool*Array
  1359. if (line.contains("empty")) {
  1360. line = reg_container.reg_is_empty.sub(line, "is_empty(", true);
  1361. }
  1362. // -- \t.func() -> \tsuper.func() Object
  1363. if (line.contains("(") && line.contains(".")) {
  1364. 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"
  1365. }
  1366. // -- JSON.parse(a) -> JSON.new().parse(a) etc. JSON
  1367. if (line.contains("parse")) {
  1368. 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);
  1369. }
  1370. // -- to_json(a) -> JSON.new().stringify(a) Object
  1371. if (line.contains("to_json")) {
  1372. line = reg_container.reg_json_to.sub(line, "JSON.new().stringify", true);
  1373. }
  1374. // -- parse_json(a) -> JSON.get_data() etc. Object
  1375. if (line.contains("parse_json")) {
  1376. 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);
  1377. }
  1378. // -- JSON.print( -> JSON.stringify(
  1379. if (line.contains("JSON.print(")) {
  1380. line = reg_container.reg_json_print.sub(line, "JSON.stringify(", true);
  1381. }
  1382. // -- get_node(@ -> get_node( Node
  1383. if (line.contains("get_node")) {
  1384. line = line.replace("get_node(@", "get_node(");
  1385. }
  1386. // export(float) var lifetime = 3.0 -> export var lifetime: float = 3.0 GDScript
  1387. if (line.contains("export")) {
  1388. line = reg_container.reg_export.sub(line, "export var $2: $1");
  1389. }
  1390. // export(String, 'AnonymousPro', 'CourierPrime') var _font_name = 'AnonymousPro' -> export var _font_name = 'AnonymousPro' #(String, 'AnonymousPro', 'CourierPrime') GDScript
  1391. if (line.contains("export")) {
  1392. line = reg_container.reg_export_advanced.sub(line, "export var $2$3 # ($1)");
  1393. }
  1394. // Setget Setget
  1395. if (line.contains("setget")) {
  1396. line = reg_container.reg_setget_setget.sub(line, "var $1$2: get = $4, set = $3", true);
  1397. }
  1398. // Setget set
  1399. if (line.contains("setget")) {
  1400. line = reg_container.reg_setget_set.sub(line, "var $1$2: set = $3", true);
  1401. }
  1402. // Setget get
  1403. if (line.contains("setget")) {
  1404. line = reg_container.reg_setget_get.sub(line, "var $1$2: get = $3", true);
  1405. }
  1406. if (line.contains("window_resizable")) {
  1407. // OS.set_window_resizable(a) -> get_window().unresizable = not (a)
  1408. line = reg_container.reg_os_set_window_resizable.sub(line, "get_window().unresizable = not ($1)", true);
  1409. // OS.window_resizable = a -> same
  1410. line = reg_container.reg_os_assign_window_resizable.sub(line, "get_window().unresizable = not ($1)", true);
  1411. // OS.[is_]window_resizable() -> (not get_window().unresizable)
  1412. line = reg_container.reg_os_is_window_resizable.sub(line, "(not get_window().unresizable)", true);
  1413. }
  1414. if (line.contains("window_fullscreen")) {
  1415. // OS.window_fullscreen(a) -> get_window().mode = Window.MODE_EXCLUSIVE_FULLSCREEN if (a) else Window.MODE_WINDOWED
  1416. line = reg_container.reg_os_set_fullscreen.sub(line, "get_window().mode = Window.MODE_EXCLUSIVE_FULLSCREEN if ($1) else Window.MODE_WINDOWED", true);
  1417. // window_fullscreen = a -> same
  1418. line = reg_container.reg_os_assign_fullscreen.sub(line, "get_window().mode = Window.MODE_EXCLUSIVE_FULLSCREEN if ($1) else Window.MODE_WINDOWED", true);
  1419. // OS.[is_]window_fullscreen() -> ((get_window().mode == Window.MODE_EXCLUSIVE_FULLSCREEN) or (get_window().mode == Window.MODE_FULLSCREEN))
  1420. line = reg_container.reg_os_is_fullscreen.sub(line, "((get_window().mode == Window.MODE_EXCLUSIVE_FULLSCREEN) or (get_window().mode == Window.MODE_FULLSCREEN))", true);
  1421. }
  1422. if (line.contains("window_maximized")) {
  1423. // OS.window_maximized(a) -> get_window().mode = Window.MODE_MAXIMIZED if (a) else Window.MODE_WINDOWED
  1424. line = reg_container.reg_os_set_maximized.sub(line, "get_window().mode = Window.MODE_MAXIMIZED if ($1) else Window.MODE_WINDOWED", true);
  1425. // window_maximized = a -> same
  1426. line = reg_container.reg_os_assign_maximized.sub(line, "get_window().mode = Window.MODE_MAXIMIZED if ($1) else Window.MODE_WINDOWED", true);
  1427. // OS.[is_]window_maximized() -> (get_window().mode == Window.MODE_MAXIMIZED)
  1428. line = reg_container.reg_os_is_maximized.sub(line, "(get_window().mode == Window.MODE_MAXIMIZED)", true);
  1429. }
  1430. if (line.contains("window_minimized")) {
  1431. // OS.window_minimized(a) -> get_window().mode = Window.MODE_MINIMIZED if (a) else Window.MODE_WINDOWED
  1432. line = reg_container.reg_os_set_minimized.sub(line, "get_window().mode = Window.MODE_MINIMIZED if ($1) else Window.MODE_WINDOWED", true);
  1433. // window_minimized = a -> same
  1434. line = reg_container.reg_os_assign_minimized.sub(line, "get_window().mode = Window.MODE_MINIMIZED if ($1) else Window.MODE_WINDOWED", true);
  1435. // OS.[is_]window_minimized() -> (get_window().mode == Window.MODE_MINIMIZED)
  1436. line = reg_container.reg_os_is_minimized.sub(line, "(get_window().mode == Window.MODE_MINIMIZED)", true);
  1437. }
  1438. if (line.contains("set_use_vsync")) {
  1439. // OS.set_use_vsync(a) -> get_window().window_set_vsync_mode(DisplayServer.VSYNC_ENABLED if (a) else DisplayServer.VSYNC_DISABLED)
  1440. line = reg_container.reg_os_set_vsync.sub(line, "DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_ENABLED if ($1) else DisplayServer.VSYNC_DISABLED)", true);
  1441. }
  1442. if (line.contains("vsync_enabled")) {
  1443. // vsync_enabled = a -> get_window().window_set_vsync_mode(DisplayServer.VSYNC_ENABLED if (a) else DisplayServer.VSYNC_DISABLED)
  1444. line = reg_container.reg_os_assign_vsync.sub(line, "DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_ENABLED if ($1) else DisplayServer.VSYNC_DISABLED)", true);
  1445. // OS.[is_]vsync_enabled() -> (DisplayServer.window_get_vsync_mode() != DisplayServer.VSYNC_DISABLED)
  1446. line = reg_container.reg_os_is_vsync.sub(line, "(DisplayServer.window_get_vsync_mode() != DisplayServer.VSYNC_DISABLED)", true);
  1447. }
  1448. if (line.contains("OS.screen_orientation")) { // keep "OS." at start
  1449. // OS.screen_orientation = a -> DisplayServer.screen_set_orientation(a)
  1450. line = reg_container.reg_os_assign_screen_orient.sub(line, "$1DisplayServer.screen_set_orientation($2)", true); // assignment
  1451. line = line.replace("OS.screen_orientation", "DisplayServer.screen_get_orientation()"); // value access
  1452. }
  1453. if (line.contains("_window_always_on_top")) {
  1454. // OS.set_window_always_on_top(a) -> get_window().always_on_top = (a)
  1455. line = reg_container.reg_os_set_always_on_top.sub(line, "get_window().always_on_top = ($1)", true);
  1456. // OS.is_window_always_on_top() -> get_window().always_on_top
  1457. line = reg_container.reg_os_is_always_on_top.sub(line, "get_window().always_on_top", true);
  1458. }
  1459. if (line.contains("et_borderless_window")) {
  1460. // OS.set_borderless_window(a) -> get_window().borderless = (a)
  1461. line = reg_container.reg_os_set_borderless.sub(line, "get_window().borderless = ($1)", true);
  1462. // OS.get_borderless_window() -> get_window().borderless
  1463. line = reg_container.reg_os_get_borderless.sub(line, "get_window().borderless", true);
  1464. }
  1465. // OS.SCREEN_ORIENTATION_* -> DisplayServer.SCREEN_*
  1466. if (line.contains("OS.SCREEN_ORIENTATION_")) {
  1467. line = reg_container.reg_os_screen_orient_enum.sub(line, "DisplayServer.SCREEN_$1", true);
  1468. }
  1469. // OS -> Window simple replacements with optional set/get.
  1470. if (line.contains("current_screen")) {
  1471. line = reg_container.reg_os_current_screen.sub(line, "get_window().$1current_screen", true);
  1472. }
  1473. if (line.contains("min_window_size")) {
  1474. line = reg_container.reg_os_min_window_size.sub(line, "get_window().$1min_size", true);
  1475. }
  1476. if (line.contains("max_window_size")) {
  1477. line = reg_container.reg_os_max_window_size.sub(line, "get_window().$1max_size", true);
  1478. }
  1479. if (line.contains("window_position")) {
  1480. line = reg_container.reg_os_window_position.sub(line, "get_window().$1position", true);
  1481. }
  1482. if (line.contains("window_size")) {
  1483. line = reg_container.reg_os_window_size.sub(line, "get_window().$1size", true);
  1484. }
  1485. if (line.contains("et_screen_orientation")) {
  1486. line = reg_container.reg_os_getset_screen_orient.sub(line, "DisplayServer.screen_$1et_orientation", true);
  1487. }
  1488. // Instantiate
  1489. if (line.contains("instance")) {
  1490. line = reg_container.reg_instantiate.sub(line, ".instantiate($1)", true);
  1491. }
  1492. // -- r.move_and_slide( a, b, c, d, e ) -> r.set_velocity(a) ... r.move_and_slide() KinematicBody
  1493. if (line.contains(("move_and_slide("))) {
  1494. int start = line.find("move_and_slide(");
  1495. int end = get_end_parenthesis(line.substr(start)) + 1;
  1496. if (end > -1) {
  1497. String base_obj = get_object_of_execution(line.substr(0, start));
  1498. String starting_space = get_starting_space(line);
  1499. Vector<String> parts = parse_arguments(line.substr(start, end));
  1500. if (parts.size() >= 1) {
  1501. String line_new;
  1502. // motion_velocity
  1503. line_new += starting_space + base_obj + "set_velocity(" + parts[0] + ")\n";
  1504. // up_direction
  1505. if (parts.size() >= 2) {
  1506. line_new += starting_space + base_obj + "set_up_direction(" + parts[1] + ")\n";
  1507. }
  1508. // stop_on_slope
  1509. if (parts.size() >= 3) {
  1510. line_new += starting_space + base_obj + "set_floor_stop_on_slope_enabled(" + parts[2] + ")\n";
  1511. }
  1512. // max_slides
  1513. if (parts.size() >= 4) {
  1514. line_new += starting_space + base_obj + "set_max_slides(" + parts[3] + ")\n";
  1515. }
  1516. // floor_max_angle
  1517. if (parts.size() >= 5) {
  1518. line_new += starting_space + base_obj + "set_floor_max_angle(" + parts[4] + ")\n";
  1519. }
  1520. // infiinite_interia
  1521. if (parts.size() >= 6) {
  1522. line_new += starting_space + "# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `" + parts[5] + "`\n";
  1523. }
  1524. line_new += starting_space + base_obj + "move_and_slide()";
  1525. if (!line.begins_with(starting_space + "move_and_slide")) {
  1526. line = line_new + "\n" + line.substr(0, start) + "velocity" + line.substr(end + start);
  1527. } else {
  1528. line = line_new + line.substr(end + start);
  1529. }
  1530. }
  1531. }
  1532. }
  1533. // -- r.move_and_slide_with_snap( a, b, c, d, e ) -> r.set_velocity(a) ... r.move_and_slide() KinematicBody
  1534. if (line.contains("move_and_slide_with_snap(")) {
  1535. int start = line.find("move_and_slide_with_snap(");
  1536. int end = get_end_parenthesis(line.substr(start)) + 1;
  1537. if (end > -1) {
  1538. String base_obj = get_object_of_execution(line.substr(0, start));
  1539. String starting_space = get_starting_space(line);
  1540. Vector<String> parts = parse_arguments(line.substr(start, end));
  1541. if (parts.size() >= 1) {
  1542. String line_new;
  1543. // motion_velocity
  1544. line_new += starting_space + base_obj + "set_velocity(" + parts[0] + ")\n";
  1545. // snap
  1546. if (parts.size() >= 2) {
  1547. line_new += starting_space + "# TODOConverter40 looks that snap in Godot 4.0 is float, not vector like in Godot 3 - previous value `" + parts[1] + "`\n";
  1548. }
  1549. // up_direction
  1550. if (parts.size() >= 3) {
  1551. line_new += starting_space + base_obj + "set_up_direction(" + parts[2] + ")\n";
  1552. }
  1553. // stop_on_slope
  1554. if (parts.size() >= 4) {
  1555. line_new += starting_space + base_obj + "set_floor_stop_on_slope_enabled(" + parts[3] + ")\n";
  1556. }
  1557. // max_slides
  1558. if (parts.size() >= 5) {
  1559. line_new += starting_space + base_obj + "set_max_slides(" + parts[4] + ")\n";
  1560. }
  1561. // floor_max_angle
  1562. if (parts.size() >= 6) {
  1563. line_new += starting_space + base_obj + "set_floor_max_angle(" + parts[5] + ")\n";
  1564. }
  1565. // infiinite_interia
  1566. if (parts.size() >= 7) {
  1567. line_new += starting_space + "# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `" + parts[6] + "`\n";
  1568. }
  1569. line_new += starting_space + base_obj + "move_and_slide()";
  1570. if (!line.begins_with(starting_space + "move_and_slide_with_snap")) {
  1571. line = line_new + "\n" + line.substr(0, start) + "velocity" + line.substr(end + start);
  1572. } else {
  1573. line = line_new + line.substr(end + start);
  1574. }
  1575. }
  1576. }
  1577. }
  1578. // -- sort_custom( a , b ) -> sort_custom(Callable( a , b )) Object
  1579. if (line.contains("sort_custom(")) {
  1580. int start = line.find("sort_custom(");
  1581. int end = get_end_parenthesis(line.substr(start)) + 1;
  1582. if (end > -1) {
  1583. Vector<String> parts = parse_arguments(line.substr(start, end));
  1584. if (parts.size() == 2) {
  1585. line = line.substr(0, start) + "sort_custom(Callable(" + parts[0] + ", " + parts[1] + "))" + line.substr(end + start);
  1586. }
  1587. }
  1588. }
  1589. // -- list_dir_begin( ) -> list_dir_begin() Object
  1590. if (line.contains("list_dir_begin(")) {
  1591. int start = line.find("list_dir_begin(");
  1592. int end = get_end_parenthesis(line.substr(start)) + 1;
  1593. if (end > -1) {
  1594. line = line.substr(0, start) + "list_dir_begin() " + line.substr(end + start) + "# TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547";
  1595. }
  1596. }
  1597. // -- draw_line(1,2,3,4,5) -> draw_line(1, 2, 3, 4) CanvasItem
  1598. if (line.contains("draw_line(")) {
  1599. int start = line.find("draw_line(");
  1600. int end = get_end_parenthesis(line.substr(start)) + 1;
  1601. if (end > -1) {
  1602. Vector<String> parts = parse_arguments(line.substr(start, end));
  1603. if (parts.size() == 5) {
  1604. line = line.substr(0, start) + "draw_line(" + parts[0] + ", " + parts[1] + ", " + parts[2] + ", " + parts[3] + ")" + line.substr(end + start);
  1605. }
  1606. }
  1607. }
  1608. // -- func c(var a, var b) -> func c(a, b)
  1609. if (line.contains("func ") && line.contains("var ")) {
  1610. int start = line.find("func ");
  1611. start = line.substr(start).find("(") + start;
  1612. int end = get_end_parenthesis(line.substr(start)) + 1;
  1613. if (end > -1) {
  1614. Vector<String> parts = parse_arguments(line.substr(start, end));
  1615. String start_string = line.substr(0, start) + "(";
  1616. for (int i = 0; i < parts.size(); i++) {
  1617. start_string += parts[i].strip_edges().trim_prefix("var ");
  1618. if (i != parts.size() - 1) {
  1619. start_string += ", ";
  1620. }
  1621. }
  1622. line = start_string + ")" + line.substr(end + start);
  1623. }
  1624. }
  1625. // -- yield(this, \"timeout\") -> await this.timeout GDScript
  1626. if (line.contains("yield(")) {
  1627. int start = line.find("yield(");
  1628. int end = get_end_parenthesis(line.substr(start)) + 1;
  1629. if (end > -1) {
  1630. Vector<String> parts = parse_arguments(line.substr(start, end));
  1631. if (parts.size() == 2) {
  1632. if (builtin) {
  1633. line = line.substr(0, start) + "await " + parts[0] + "." + parts[1].replace("\\\"", "").replace("\\'", "").replace(" ", "") + line.substr(end + start);
  1634. } else {
  1635. line = line.substr(0, start) + "await " + parts[0] + "." + parts[1].replace("\"", "").replace("\'", "").replace(" ", "") + line.substr(end + start);
  1636. }
  1637. }
  1638. }
  1639. }
  1640. // -- parse_json( AA ) -> TODO Object
  1641. if (line.contains("parse_json(")) {
  1642. int start = line.find("parse_json(");
  1643. int end = get_end_parenthesis(line.substr(start)) + 1;
  1644. if (end > -1) {
  1645. Vector<String> parts = parse_arguments(line.substr(start, end));
  1646. line = line.substr(0, start) + "JSON.new().stringify(" + connect_arguments(parts, 0) + ")" + line.substr(end + start);
  1647. }
  1648. }
  1649. // -- .xform(Vector3(a,b,c)) -> * Vector3(a,b,c) Transform
  1650. if (line.contains(".xform(")) {
  1651. int start = line.find(".xform(");
  1652. int end = get_end_parenthesis(line.substr(start)) + 1;
  1653. if (end > -1) {
  1654. Vector<String> parts = parse_arguments(line.substr(start, end));
  1655. if (parts.size() == 1) {
  1656. line = line.substr(0, start) + " * (" + parts[0] + ")" + line.substr(end + start);
  1657. }
  1658. }
  1659. }
  1660. // -- .xform_inv(Vector3(a,b,c)) -> * Vector3(a,b,c) Transform
  1661. if (line.contains(".xform_inv(")) {
  1662. int start = line.find(".xform_inv(");
  1663. int end = get_end_parenthesis(line.substr(start)) + 1;
  1664. if (end > -1) {
  1665. String object_exec = get_object_of_execution(line.substr(0, start));
  1666. if (line.contains(object_exec + ".xform")) {
  1667. int start2 = line.find(object_exec + ".xform");
  1668. Vector<String> parts = parse_arguments(line.substr(start, end));
  1669. if (parts.size() == 1) {
  1670. line = line.substr(0, start2) + "(" + parts[0] + ") * " + object_exec + line.substr(end + start);
  1671. }
  1672. }
  1673. }
  1674. }
  1675. // -- "(connect(A,B,C,D,E) != OK):", "(connect(A, Callable(B, C).bind(D), E) Object
  1676. if (line.contains("connect(")) {
  1677. int start = line.find("connect(");
  1678. // Protection from disconnect
  1679. if (start == 0 || line.get(start - 1) != 's') {
  1680. int end = get_end_parenthesis(line.substr(start)) + 1;
  1681. if (end > -1) {
  1682. Vector<String> parts = parse_arguments(line.substr(start, end));
  1683. if (parts.size() == 3) {
  1684. line = line.substr(0, start) + "connect(" + parts[0] + ", Callable(" + parts[1] + ", " + parts[2] + "))" + line.substr(end + start);
  1685. } else if (parts.size() >= 4) {
  1686. 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);
  1687. }
  1688. }
  1689. }
  1690. }
  1691. // -- disconnect(a,b,c) -> disconnect(a,Callable(b,c)) Object
  1692. if (line.contains("disconnect(")) {
  1693. int start = line.find("disconnect(");
  1694. int end = get_end_parenthesis(line.substr(start)) + 1;
  1695. if (end > -1) {
  1696. Vector<String> parts = parse_arguments(line.substr(start, end));
  1697. if (parts.size() == 3) {
  1698. line = line.substr(0, start) + "disconnect(" + parts[0] + ", Callable(" + parts[1] + ", " + parts[2] + "))" + line.substr(end + start);
  1699. }
  1700. }
  1701. }
  1702. // -- is_connected(a,b,c) -> is_connected(a,Callable(b,c)) Object
  1703. if (line.contains("is_connected(")) {
  1704. int start = line.find("is_connected(");
  1705. int end = get_end_parenthesis(line.substr(start)) + 1;
  1706. if (end > -1) {
  1707. Vector<String> parts = parse_arguments(line.substr(start, end));
  1708. if (parts.size() == 3) {
  1709. line = line.substr(0, start) + "is_connected(" + parts[0] + ", Callable(" + parts[1] + ", " + parts[2] + "))" + line.substr(end + start);
  1710. }
  1711. }
  1712. }
  1713. // -- "(tween_method(A,B,C,D,E) != OK):", "(tween_method(Callable(A,B),C,D,E) Object
  1714. // -- "(tween_method(A,B,C,D,E,[F,G]) != OK):", "(tween_method(Callable(A,B).bind(F,G),C,D,E) Object
  1715. if (line.contains("tween_method(")) {
  1716. int start = line.find("tween_method(");
  1717. int end = get_end_parenthesis(line.substr(start)) + 1;
  1718. if (end > -1) {
  1719. Vector<String> parts = parse_arguments(line.substr(start, end));
  1720. if (parts.size() == 5) {
  1721. line = line.substr(0, start) + "tween_method(Callable(" + parts[0] + ", " + parts[1] + "), " + parts[2] + ", " + parts[3] + ", " + parts[4] + ")" + line.substr(end + start);
  1722. } else if (parts.size() >= 6) {
  1723. 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);
  1724. }
  1725. }
  1726. }
  1727. // -- "(tween_callback(A,B,[C,D]) != OK):", "(connect(Callable(A,B).bind(C,D)) Object
  1728. if (line.contains("tween_callback(")) {
  1729. int start = line.find("tween_callback(");
  1730. int end = get_end_parenthesis(line.substr(start)) + 1;
  1731. if (end > -1) {
  1732. Vector<String> parts = parse_arguments(line.substr(start, end));
  1733. if (parts.size() == 2) {
  1734. line = line.substr(0, start) + "tween_callback(Callable(" + parts[0] + ", " + parts[1] + "))" + line.substr(end + start);
  1735. } else if (parts.size() >= 3) {
  1736. 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);
  1737. }
  1738. }
  1739. }
  1740. // -- start(a,b) -> start(Callable(a, b)) Thread
  1741. // -- start(a,b,c,d) -> start(Callable(a, b).bind(c), d) Thread
  1742. if (line.contains("start(")) {
  1743. int start = line.find("start(");
  1744. int end = get_end_parenthesis(line.substr(start)) + 1;
  1745. // Protection from 'func start'
  1746. if (!line.begins_with("func ")) {
  1747. if (end > -1) {
  1748. Vector<String> parts = parse_arguments(line.substr(start, end));
  1749. if (parts.size() == 2) {
  1750. line = line.substr(0, start) + "start(Callable(" + parts[0] + ", " + parts[1] + "))" + line.substr(end + start);
  1751. } else if (parts.size() >= 3) {
  1752. line = line.substr(0, start) + "start(Callable(" + parts[0] + ", " + parts[1] + ").bind(" + parts[2] + ")" + connect_arguments(parts, 3) + ")" + line.substr(end + start);
  1753. }
  1754. }
  1755. }
  1756. }
  1757. // -- func _init(p_x:int).(p_x): -> func _init(p_x:int):\n\tsuper(p_x) Object # https://github.com/godotengine/godot/issues/70542
  1758. if (line.contains(" _init(") && line.rfind(":") > 0) {
  1759. // func _init(p_arg1).(super4, super5, super6)->void:
  1760. // ^--^indent ^super_start super_end^
  1761. int indent = line.count("\t", 0, line.find("func"));
  1762. int super_start = line.find(".(");
  1763. int super_end = line.rfind(")");
  1764. if (super_start > 0 && super_end > super_start) {
  1765. 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);
  1766. }
  1767. }
  1768. // assert(speed < 20, str(randi()%10)) -> assert(speed < 20) #,str(randi()%10)) GDScript - GDScript bug constant message
  1769. if (line.contains("assert(")) {
  1770. int start = line.find("assert(");
  1771. int end = get_end_parenthesis(line.substr(start)) + 1;
  1772. if (end > -1) {
  1773. Vector<String> parts = parse_arguments(line.substr(start, end));
  1774. if (parts.size() == 2) {
  1775. line = line.substr(0, start) + "assert(" + parts[0] + ") " + line.substr(end + start) + "#," + parts[1] + ")";
  1776. }
  1777. }
  1778. }
  1779. // create_from_image(aa, bb) -> create_from_image(aa) #, bb ImageTexture
  1780. if (line.contains("create_from_image(")) {
  1781. int start = line.find("create_from_image(");
  1782. int end = get_end_parenthesis(line.substr(start)) + 1;
  1783. if (end > -1) {
  1784. Vector<String> parts = parse_arguments(line.substr(start, end));
  1785. if (parts.size() == 2) {
  1786. line = line.substr(0, start) + "create_from_image(" + parts[0] + ") " + "#," + parts[1] + line.substr(end + start);
  1787. }
  1788. }
  1789. }
  1790. // set_cell_item(a, b, c, d ,e) -> set_cell_item(Vector3(a, b, c), d ,e)
  1791. if (line.contains("set_cell_item(")) {
  1792. int start = line.find("set_cell_item(");
  1793. int end = get_end_parenthesis(line.substr(start)) + 1;
  1794. if (end > -1) {
  1795. Vector<String> parts = parse_arguments(line.substr(start, end));
  1796. if (parts.size() > 2) {
  1797. line = line.substr(0, start) + "set_cell_item(Vector3(" + parts[0] + ", " + parts[1] + ", " + parts[2] + ")" + connect_arguments(parts, 3).lstrip(" ") + ")" + line.substr(end + start);
  1798. }
  1799. }
  1800. }
  1801. // get_cell_item(a, b, c) -> get_cell_item(Vector3i(a, b, c))
  1802. if (line.contains("get_cell_item(")) {
  1803. int start = line.find("get_cell_item(");
  1804. int end = get_end_parenthesis(line.substr(start)) + 1;
  1805. if (end > -1) {
  1806. Vector<String> parts = parse_arguments(line.substr(start, end));
  1807. if (parts.size() == 3) {
  1808. line = line.substr(0, start) + "get_cell_item(Vector3i(" + parts[0] + ", " + parts[1] + ", " + parts[2] + "))" + line.substr(end + start);
  1809. }
  1810. }
  1811. }
  1812. // get_cell_item_orientation(a, b, c) -> get_cell_item_orientation(Vector3i(a, b, c))
  1813. if (line.contains("get_cell_item_orientation(")) {
  1814. int start = line.find("get_cell_item_orientation(");
  1815. int end = get_end_parenthesis(line.substr(start)) + 1;
  1816. if (end > -1) {
  1817. Vector<String> parts = parse_arguments(line.substr(start, end));
  1818. if (parts.size() == 3) {
  1819. line = line.substr(0, start) + "get_cell_item_orientation(Vector3i(" + parts[0] + ", " + parts[1] + ", " + parts[2] + "))" + line.substr(end + start);
  1820. }
  1821. }
  1822. }
  1823. // apply_impulse(A, B) -> apply_impulse(B, A)
  1824. if (line.contains("apply_impulse(")) {
  1825. int start = line.find("apply_impulse(");
  1826. int end = get_end_parenthesis(line.substr(start)) + 1;
  1827. if (end > -1) {
  1828. Vector<String> parts = parse_arguments(line.substr(start, end));
  1829. if (parts.size() == 2) {
  1830. line = line.substr(0, start) + "apply_impulse(" + parts[1] + ", " + parts[0] + ")" + line.substr(end + start);
  1831. }
  1832. }
  1833. }
  1834. // apply_force(A, B) -> apply_force(B, A)
  1835. if (line.contains("apply_force(")) {
  1836. int start = line.find("apply_force(");
  1837. int end = get_end_parenthesis(line.substr(start)) + 1;
  1838. if (end > -1) {
  1839. Vector<String> parts = parse_arguments(line.substr(start, end));
  1840. if (parts.size() == 2) {
  1841. line = line.substr(0, start) + "apply_force(" + parts[1] + ", " + parts[0] + ")" + line.substr(end + start);
  1842. }
  1843. }
  1844. }
  1845. // map_to_world(a, b, c) -> map_to_local(Vector3i(a, b, c))
  1846. if (line.contains("map_to_world(")) {
  1847. int start = line.find("map_to_world(");
  1848. int end = get_end_parenthesis(line.substr(start)) + 1;
  1849. if (end > -1) {
  1850. Vector<String> parts = parse_arguments(line.substr(start, end));
  1851. if (parts.size() == 3) {
  1852. line = line.substr(0, start) + "map_to_local(Vector3i(" + parts[0] + ", " + parts[1] + ", " + parts[2] + "))" + line.substr(end + start);
  1853. } else if (parts.size() == 1) {
  1854. line = line.substr(0, start) + "map_to_local(" + parts[0] + ")" + line.substr(end + start);
  1855. }
  1856. }
  1857. }
  1858. // set_rotating(true) -> set_ignore_rotation(false)
  1859. if (line.contains("set_rotating(")) {
  1860. int start = line.find("set_rotating(");
  1861. int end = get_end_parenthesis(line.substr(start)) + 1;
  1862. if (end > -1) {
  1863. Vector<String> parts = parse_arguments(line.substr(start, end));
  1864. if (parts.size() == 1) {
  1865. String opposite = parts[0] == "true" ? "false" : "true";
  1866. line = line.substr(0, start) + "set_ignore_rotation(" + opposite + ")";
  1867. }
  1868. }
  1869. }
  1870. // OS.get_window_safe_area() -> DisplayServer.get_display_safe_area()
  1871. if (line.contains("OS.get_window_safe_area(")) {
  1872. int start = line.find("OS.get_window_safe_area(");
  1873. int end = get_end_parenthesis(line.substr(start)) + 1;
  1874. if (end > -1) {
  1875. Vector<String> parts = parse_arguments(line.substr(start, end));
  1876. if (parts.size() == 0) {
  1877. line = line.substr(0, start) + "DisplayServer.get_display_safe_area()" + line.substr(end + start);
  1878. }
  1879. }
  1880. }
  1881. // draw_rect(a,b,c,d,e) -> draw_rect(a,b,c,d)#e) TODOGODOT4 Antialiasing argument is missing
  1882. if (line.contains("draw_rect(")) {
  1883. int start = line.find("draw_rect(");
  1884. int end = get_end_parenthesis(line.substr(start)) + 1;
  1885. if (end > -1) {
  1886. Vector<String> parts = parse_arguments(line.substr(start, end));
  1887. if (parts.size() == 5) {
  1888. line = line.substr(0, start) + "draw_rect(" + parts[0] + ", " + parts[1] + ", " + parts[2] + ", " + parts[3] + ")" + line.substr(end + start) + "# " + parts[4] + ") TODOGODOT4 Antialiasing argument is missing";
  1889. }
  1890. }
  1891. }
  1892. // get_focus_owner() -> get_viewport().gui_get_focus_owner()
  1893. if (line.contains("get_focus_owner()")) {
  1894. line = line.replace("get_focus_owner()", "get_viewport().gui_get_focus_owner()");
  1895. }
  1896. // button.pressed = 1 -> button.button_pressed = 1
  1897. if (line.contains(".pressed")) {
  1898. int start = line.find(".pressed");
  1899. bool foundNextEqual = false;
  1900. String line_to_check = line.substr(start + String(".pressed").length());
  1901. for (int current_index = 0; line_to_check.length() > current_index; current_index++) {
  1902. char32_t chr = line_to_check.get(current_index);
  1903. if (chr == '\t' || chr == ' ') {
  1904. continue;
  1905. } else if (chr == '=') {
  1906. foundNextEqual = true;
  1907. } else {
  1908. break;
  1909. }
  1910. }
  1911. if (foundNextEqual) {
  1912. line = line.substr(0, start) + ".button_pressed" + line.substr(start + String(".pressed").length());
  1913. }
  1914. }
  1915. // rotating = true -> ignore_rotation = false # reversed "rotating" for Camera2D
  1916. if (line.contains("rotating")) {
  1917. int start = line.find("rotating");
  1918. bool foundNextEqual = false;
  1919. String line_to_check = line.substr(start + String("rotating").length());
  1920. String assigned_value;
  1921. for (int current_index = 0; line_to_check.length() > current_index; current_index++) {
  1922. char32_t chr = line_to_check.get(current_index);
  1923. if (chr == '\t' || chr == ' ') {
  1924. continue;
  1925. } else if (chr == '=') {
  1926. foundNextEqual = true;
  1927. assigned_value = line.right(current_index).strip_edges();
  1928. assigned_value = assigned_value == "true" ? "false" : "true";
  1929. } else {
  1930. break;
  1931. }
  1932. }
  1933. if (foundNextEqual) {
  1934. line = line.substr(0, start) + "ignore_rotation =" + assigned_value + " # reversed \"rotating\" for Camera2D";
  1935. }
  1936. }
  1937. // OS -> Time functions
  1938. if (line.contains("OS.get_ticks_msec")) {
  1939. line = line.replace("OS.get_ticks_msec", "Time.get_ticks_msec");
  1940. }
  1941. if (line.contains("OS.get_ticks_usec")) {
  1942. line = line.replace("OS.get_ticks_usec", "Time.get_ticks_usec");
  1943. }
  1944. if (line.contains("OS.get_unix_time")) {
  1945. line = line.replace("OS.get_unix_time", "Time.get_unix_time_from_system");
  1946. }
  1947. if (line.contains("OS.get_datetime")) {
  1948. line = line.replace("OS.get_datetime", "Time.get_datetime_dict_from_system");
  1949. }
  1950. // OS -> DisplayServer
  1951. if (line.contains("OS.get_display_cutouts")) {
  1952. line = line.replace("OS.get_display_cutouts", "DisplayServer.get_display_cutouts");
  1953. }
  1954. if (line.contains("OS.get_screen_count")) {
  1955. line = line.replace("OS.get_screen_count", "DisplayServer.get_screen_count");
  1956. }
  1957. if (line.contains("OS.get_screen_dpi")) {
  1958. line = line.replace("OS.get_screen_dpi", "DisplayServer.screen_get_dpi");
  1959. }
  1960. if (line.contains("OS.get_screen_max_scale")) {
  1961. line = line.replace("OS.get_screen_max_scale", "DisplayServer.screen_get_max_scale");
  1962. }
  1963. if (line.contains("OS.get_screen_position")) {
  1964. line = line.replace("OS.get_screen_position", "DisplayServer.screen_get_position");
  1965. }
  1966. if (line.contains("OS.get_screen_refresh_rate")) {
  1967. line = line.replace("OS.get_screen_refresh_rate", "DisplayServer.screen_get_refresh_rate");
  1968. }
  1969. if (line.contains("OS.get_screen_scale")) {
  1970. line = line.replace("OS.get_screen_scale", "DisplayServer.screen_get_scale");
  1971. }
  1972. if (line.contains("OS.get_screen_size")) {
  1973. line = line.replace("OS.get_screen_size", "DisplayServer.screen_get_size");
  1974. }
  1975. if (line.contains("OS.set_icon")) {
  1976. line = line.replace("OS.set_icon", "DisplayServer.set_icon");
  1977. }
  1978. if (line.contains("OS.set_native_icon")) {
  1979. line = line.replace("OS.set_native_icon", "DisplayServer.set_native_icon");
  1980. }
  1981. // OS -> Window
  1982. if (line.contains("OS.window_borderless")) {
  1983. line = line.replace("OS.window_borderless", "get_window().borderless");
  1984. }
  1985. if (line.contains("OS.get_real_window_size")) {
  1986. line = line.replace("OS.get_real_window_size", "get_window().get_size_with_decorations");
  1987. }
  1988. if (line.contains("OS.is_window_focused")) {
  1989. line = line.replace("OS.is_window_focused", "get_window().has_focus");
  1990. }
  1991. if (line.contains("OS.move_window_to_foreground")) {
  1992. line = line.replace("OS.move_window_to_foreground", "get_window().move_to_foreground");
  1993. }
  1994. if (line.contains("OS.request_attention")) {
  1995. line = line.replace("OS.request_attention", "get_window().request_attention");
  1996. }
  1997. if (line.contains("OS.set_window_title")) {
  1998. line = line.replace("OS.set_window_title", "get_window().set_title");
  1999. }
  2000. // get_tree().set_input_as_handled() -> get_viewport().set_input_as_handled()
  2001. if (line.contains("get_tree().set_input_as_handled()")) {
  2002. line = line.replace("get_tree().set_input_as_handled()", "get_viewport().set_input_as_handled()");
  2003. }
  2004. // Fix the simple case of using _unhandled_key_input
  2005. // func _unhandled_key_input(event: InputEventKey) -> _unhandled_key_input(event: InputEvent)
  2006. if (line.contains("_unhandled_key_input(event: InputEventKey)")) {
  2007. line = line.replace("_unhandled_key_input(event: InputEventKey)", "_unhandled_key_input(event: InputEvent)");
  2008. }
  2009. if (line.contains("Engine.editor_hint")) {
  2010. line = line.replace("Engine.editor_hint", "Engine.is_editor_hint()");
  2011. }
  2012. }
  2013. void ProjectConverter3To4::process_csharp_line(String &line, const RegExContainer &reg_container) {
  2014. line = line.replace("OS.GetWindowSafeArea()", "DisplayServer.ScreenGetUsableRect()");
  2015. // GetTree().SetInputAsHandled() -> GetViewport().SetInputAsHandled()
  2016. if (line.contains("GetTree().SetInputAsHandled()")) {
  2017. line = line.replace("GetTree().SetInputAsHandled()", "GetViewport().SetInputAsHandled()");
  2018. }
  2019. // Fix the simple case of using _UnhandledKeyInput
  2020. // func _UnhandledKeyInput(InputEventKey @event) -> _UnhandledKeyInput(InputEvent @event)
  2021. if (line.contains("_UnhandledKeyInput(InputEventKey @event)")) {
  2022. line = line.replace("_UnhandledKeyInput(InputEventKey @event)", "_UnhandledKeyInput(InputEvent @event)");
  2023. }
  2024. // -- Connect(,,,things) -> Connect(,Callable(,),things) Object
  2025. if (line.contains("Connect(")) {
  2026. int start = line.find("Connect(");
  2027. // Protection from disconnect
  2028. if (start == 0 || line.get(start - 1) != 's') {
  2029. int end = get_end_parenthesis(line.substr(start)) + 1;
  2030. if (end > -1) {
  2031. Vector<String> parts = parse_arguments(line.substr(start, end));
  2032. if (parts.size() >= 3) {
  2033. line = line.substr(0, start) + "Connect(" + parts[0] + ", new Callable(" + parts[1] + ", " + parts[2] + ")" + connect_arguments(parts, 3) + ")" + line.substr(end + start);
  2034. }
  2035. }
  2036. }
  2037. }
  2038. // -- Disconnect(a,b,c) -> Disconnect(a,Callable(b,c)) Object
  2039. if (line.contains("Disconnect(")) {
  2040. int start = line.find("Disconnect(");
  2041. int end = get_end_parenthesis(line.substr(start)) + 1;
  2042. if (end > -1) {
  2043. Vector<String> parts = parse_arguments(line.substr(start, end));
  2044. if (parts.size() == 3) {
  2045. line = line.substr(0, start) + "Disconnect(" + parts[0] + ", new Callable(" + parts[1] + ", " + parts[2] + "))" + line.substr(end + start);
  2046. }
  2047. }
  2048. }
  2049. // -- IsConnected(a,b,c) -> IsConnected(a,Callable(b,c)) Object
  2050. if (line.contains("IsConnected(")) {
  2051. int start = line.find("IsConnected(");
  2052. int end = get_end_parenthesis(line.substr(start)) + 1;
  2053. if (end > -1) {
  2054. Vector<String> parts = parse_arguments(line.substr(start, end));
  2055. if (parts.size() == 3) {
  2056. line = line.substr(0, start) + "IsConnected(" + parts[0] + ", new Callable(" + parts[1] + ", " + parts[2] + "))" + line.substr(end + start);
  2057. }
  2058. }
  2059. }
  2060. }
  2061. void ProjectConverter3To4::rename_csharp_functions(Vector<SourceLine> &source_lines, const RegExContainer &reg_container) {
  2062. for (SourceLine &source_line : source_lines) {
  2063. if (source_line.is_comment) {
  2064. continue;
  2065. }
  2066. String &line = source_line.line;
  2067. if (uint64_t(line.length()) <= maximum_line_length) {
  2068. process_csharp_line(line, reg_container);
  2069. }
  2070. }
  2071. };
  2072. Vector<String> ProjectConverter3To4::check_for_rename_csharp_functions(Vector<String> &lines, const RegExContainer &reg_container) {
  2073. int current_line = 1;
  2074. Vector<String> found_renames;
  2075. for (String &line : lines) {
  2076. if (uint64_t(line.length()) <= maximum_line_length) {
  2077. String old_line = line;
  2078. process_csharp_line(line, reg_container);
  2079. if (old_line != line) {
  2080. found_renames.append(simple_line_formatter(current_line, old_line, line));
  2081. }
  2082. }
  2083. }
  2084. return found_renames;
  2085. }
  2086. void ProjectConverter3To4::rename_csharp_attributes(Vector<SourceLine> &source_lines, const RegExContainer &reg_container) {
  2087. 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";
  2088. for (SourceLine &source_line : source_lines) {
  2089. if (source_line.is_comment) {
  2090. continue;
  2091. }
  2092. String &line = source_line.line;
  2093. if (uint64_t(line.length()) <= maximum_line_length) {
  2094. line = reg_container.keyword_csharp_remote.sub(line, "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", true);
  2095. line = reg_container.keyword_csharp_remotesync.sub(line, "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", true);
  2096. line = reg_container.keyword_csharp_puppet.sub(line, "[RPC]", true);
  2097. line = reg_container.keyword_csharp_puppetsync.sub(line, "[RPC(CallLocal = true)]", true);
  2098. line = reg_container.keyword_csharp_master.sub(line, error_message + "[RPC]", true);
  2099. line = reg_container.keyword_csharp_mastersync.sub(line, error_message + "[RPC(CallLocal = true)]", true);
  2100. }
  2101. }
  2102. }
  2103. Vector<String> ProjectConverter3To4::check_for_rename_csharp_attributes(Vector<String> &lines, const RegExContainer &reg_container) {
  2104. int current_line = 1;
  2105. Vector<String> found_renames;
  2106. for (String &line : lines) {
  2107. if (uint64_t(line.length()) <= maximum_line_length) {
  2108. String old;
  2109. old = line;
  2110. line = reg_container.keyword_csharp_remote.sub(line, "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", true);
  2111. if (old != line) {
  2112. found_renames.append(line_formatter(current_line, "[Remote]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", line));
  2113. }
  2114. old = line;
  2115. line = reg_container.keyword_csharp_remotesync.sub(line, "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", true);
  2116. if (old != line) {
  2117. found_renames.append(line_formatter(current_line, "[RemoteSync]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", line));
  2118. }
  2119. old = line;
  2120. line = reg_container.keyword_csharp_puppet.sub(line, "[RPC]", true);
  2121. if (old != line) {
  2122. found_renames.append(line_formatter(current_line, "[Puppet]", "[RPC]", line));
  2123. }
  2124. old = line;
  2125. line = reg_container.keyword_csharp_puppetsync.sub(line, "[RPC(CallLocal = true)]", true);
  2126. if (old != line) {
  2127. found_renames.append(line_formatter(current_line, "[PuppetSync]", "[RPC(CallLocal = true)]", line));
  2128. }
  2129. old = line;
  2130. line = reg_container.keyword_csharp_master.sub(line, "[RPC]", true);
  2131. if (old != line) {
  2132. found_renames.append(line_formatter(current_line, "[Master]", "[RPC]", line));
  2133. }
  2134. old = line;
  2135. line = reg_container.keyword_csharp_mastersync.sub(line, "[RPC(CallLocal = true)]", true);
  2136. if (old != line) {
  2137. found_renames.append(line_formatter(current_line, "[MasterSync]", "[RPC(CallLocal = true)]", line));
  2138. }
  2139. }
  2140. current_line++;
  2141. }
  2142. return found_renames;
  2143. }
  2144. void ProjectConverter3To4::rename_gdscript_keywords(Vector<SourceLine> &source_lines, const RegExContainer &reg_container) {
  2145. 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";
  2146. for (SourceLine &source_line : source_lines) {
  2147. if (source_line.is_comment) {
  2148. continue;
  2149. }
  2150. String &line = source_line.line;
  2151. if (uint64_t(line.length()) <= maximum_line_length) {
  2152. if (line.contains("export")) {
  2153. line = reg_container.keyword_gdscript_export_single.sub(line, "@export", true);
  2154. }
  2155. if (line.contains("export")) {
  2156. line = reg_container.keyword_gdscript_export_mutli.sub(line, "$1@export", true);
  2157. }
  2158. if (line.contains("onready")) {
  2159. line = reg_container.keyword_gdscript_onready.sub(line, "@onready", true);
  2160. }
  2161. if (line.contains("remote")) {
  2162. line = reg_container.keyword_gdscript_remote.sub(line, "@rpc(\"any_peer\") func", true);
  2163. }
  2164. if (line.contains("remote")) {
  2165. line = reg_container.keyword_gdscript_remotesync.sub(line, "@rpc(\"any_peer\", \"call_local\") func", true);
  2166. }
  2167. if (line.contains("sync")) {
  2168. line = reg_container.keyword_gdscript_sync.sub(line, "@rpc(\"any_peer\", \"call_local\") func", true);
  2169. }
  2170. if (line.contains("slave")) {
  2171. line = reg_container.keyword_gdscript_slave.sub(line, "@rpc func", true);
  2172. }
  2173. if (line.contains("puppet")) {
  2174. line = reg_container.keyword_gdscript_puppet.sub(line, "@rpc func", true);
  2175. }
  2176. if (line.contains("puppet")) {
  2177. line = reg_container.keyword_gdscript_puppetsync.sub(line, "@rpc(\"call_local\") func", true);
  2178. }
  2179. if (line.contains("master")) {
  2180. line = reg_container.keyword_gdscript_master.sub(line, error_message + "@rpc func", true);
  2181. }
  2182. if (line.contains("master")) {
  2183. line = reg_container.keyword_gdscript_mastersync.sub(line, error_message + "@rpc(\"call_local\") func", true);
  2184. }
  2185. }
  2186. }
  2187. }
  2188. Vector<String> ProjectConverter3To4::check_for_rename_gdscript_keywords(Vector<String> &lines, const RegExContainer &reg_container) {
  2189. Vector<String> found_renames;
  2190. int current_line = 1;
  2191. for (String &line : lines) {
  2192. if (uint64_t(line.length()) <= maximum_line_length) {
  2193. String old;
  2194. if (line.contains("tool")) {
  2195. old = line;
  2196. line = reg_container.keyword_gdscript_tool.sub(line, "@tool", true);
  2197. if (old != line) {
  2198. found_renames.append(line_formatter(current_line, "tool", "@tool", line));
  2199. }
  2200. }
  2201. if (line.contains("export")) {
  2202. old = line;
  2203. line = reg_container.keyword_gdscript_export_single.sub(line, "$1@export", true);
  2204. if (old != line) {
  2205. found_renames.append(line_formatter(current_line, "export", "@export", line));
  2206. }
  2207. }
  2208. if (line.contains("export")) {
  2209. old = line;
  2210. line = reg_container.keyword_gdscript_export_mutli.sub(line, "@export", true);
  2211. if (old != line) {
  2212. found_renames.append(line_formatter(current_line, "export", "@export", line));
  2213. }
  2214. }
  2215. if (line.contains("onready")) {
  2216. old = line;
  2217. line = reg_container.keyword_gdscript_tool.sub(line, "@onready", true);
  2218. if (old != line) {
  2219. found_renames.append(line_formatter(current_line, "onready", "@onready", line));
  2220. }
  2221. }
  2222. if (line.contains("remote")) {
  2223. old = line;
  2224. line = reg_container.keyword_gdscript_remote.sub(line, "@rpc(\"any_peer\") func", true);
  2225. if (old != line) {
  2226. found_renames.append(line_formatter(current_line, "remote func", "@rpc(\"any_peer\") func", line));
  2227. }
  2228. }
  2229. if (line.contains("remote")) {
  2230. old = line;
  2231. line = reg_container.keyword_gdscript_remotesync.sub(line, "@rpc(\"any_peer\", \"call_local\")) func", true);
  2232. if (old != line) {
  2233. found_renames.append(line_formatter(current_line, "remotesync func", "@rpc(\"any_peer\", \"call_local\")) func", line));
  2234. }
  2235. }
  2236. if (line.contains("sync")) {
  2237. old = line;
  2238. line = reg_container.keyword_gdscript_sync.sub(line, "@rpc(\"any_peer\", \"call_local\")) func", true);
  2239. if (old != line) {
  2240. found_renames.append(line_formatter(current_line, "sync func", "@rpc(\"any_peer\", \"call_local\")) func", line));
  2241. }
  2242. }
  2243. if (line.contains("slave")) {
  2244. old = line;
  2245. line = reg_container.keyword_gdscript_slave.sub(line, "@rpc func", true);
  2246. if (old != line) {
  2247. found_renames.append(line_formatter(current_line, "slave func", "@rpc func", line));
  2248. }
  2249. }
  2250. if (line.contains("puppet")) {
  2251. old = line;
  2252. line = reg_container.keyword_gdscript_puppet.sub(line, "@rpc func", true);
  2253. if (old != line) {
  2254. found_renames.append(line_formatter(current_line, "puppet func", "@rpc func", line));
  2255. }
  2256. }
  2257. if (line.contains("puppet")) {
  2258. old = line;
  2259. line = reg_container.keyword_gdscript_puppetsync.sub(line, "@rpc(\"call_local\") func", true);
  2260. if (old != line) {
  2261. found_renames.append(line_formatter(current_line, "puppetsync func", "@rpc(\"call_local\") func", line));
  2262. }
  2263. }
  2264. if (line.contains("master")) {
  2265. old = line;
  2266. line = reg_container.keyword_gdscript_master.sub(line, "@rpc func", true);
  2267. if (old != line) {
  2268. found_renames.append(line_formatter(current_line, "master func", "@rpc func", line));
  2269. }
  2270. }
  2271. if (line.contains("master")) {
  2272. old = line;
  2273. line = reg_container.keyword_gdscript_master.sub(line, "@rpc(\"call_local\") func", true);
  2274. if (old != line) {
  2275. found_renames.append(line_formatter(current_line, "mastersync func", "@rpc(\"call_local\") func", line));
  2276. }
  2277. }
  2278. }
  2279. current_line++;
  2280. }
  2281. return found_renames;
  2282. }
  2283. void ProjectConverter3To4::rename_input_map_scancode(Vector<SourceLine> &source_lines, const RegExContainer &reg_container) {
  2284. // The old Special Key, now colliding with CMD_OR_CTRL.
  2285. const int old_spkey = (1 << 24);
  2286. for (SourceLine &source_line : source_lines) {
  2287. if (source_line.is_comment) {
  2288. continue;
  2289. }
  2290. String &line = source_line.line;
  2291. if (uint64_t(line.length()) <= maximum_line_length) {
  2292. TypedArray<RegExMatch> reg_match = reg_container.input_map_keycode.search_all(line);
  2293. for (int i = 0; i < reg_match.size(); ++i) {
  2294. Ref<RegExMatch> match = reg_match[i];
  2295. PackedStringArray strings = match->get_strings();
  2296. int key = strings[3].to_int();
  2297. if (key & old_spkey) {
  2298. // Create new key, clearing old Special Key and setting new one.
  2299. key = (key & ~old_spkey) | (int)Key::SPECIAL;
  2300. line = line.replace(strings[0], String(",\"") + strings[1] + "scancode\":" + String::num_int64(key));
  2301. }
  2302. }
  2303. }
  2304. }
  2305. }
  2306. Vector<String> ProjectConverter3To4::check_for_rename_input_map_scancode(Vector<String> &lines, const RegExContainer &reg_container) {
  2307. Vector<String> found_renames;
  2308. // The old Special Key, now colliding with CMD_OR_CTRL.
  2309. const int old_spkey = (1 << 24);
  2310. int current_line = 1;
  2311. for (String &line : lines) {
  2312. if (uint64_t(line.length()) <= maximum_line_length) {
  2313. TypedArray<RegExMatch> reg_match = reg_container.input_map_keycode.search_all(line);
  2314. for (int i = 0; i < reg_match.size(); ++i) {
  2315. Ref<RegExMatch> match = reg_match[i];
  2316. PackedStringArray strings = match->get_strings();
  2317. int key = strings[3].to_int();
  2318. if (key & old_spkey) {
  2319. // Create new key, clearing old Special Key and setting new one.
  2320. key = (key & ~old_spkey) | (int)Key::SPECIAL;
  2321. found_renames.append(line_formatter(current_line, strings[3], String::num_int64(key), line));
  2322. }
  2323. }
  2324. }
  2325. current_line++;
  2326. }
  2327. return found_renames;
  2328. }
  2329. void ProjectConverter3To4::custom_rename(Vector<SourceLine> &source_lines, String from, String to) {
  2330. RegEx reg = RegEx(String("\\b") + from + "\\b");
  2331. CRASH_COND(!reg.is_valid());
  2332. for (SourceLine &source_line : source_lines) {
  2333. if (source_line.is_comment) {
  2334. continue;
  2335. }
  2336. String &line = source_line.line;
  2337. if (uint64_t(line.length()) <= maximum_line_length) {
  2338. line = reg.sub(line, to, true);
  2339. }
  2340. }
  2341. };
  2342. Vector<String> ProjectConverter3To4::check_for_custom_rename(Vector<String> &lines, String from, String to) {
  2343. Vector<String> found_renames;
  2344. RegEx reg = RegEx(String("\\b") + from + "\\b");
  2345. CRASH_COND(!reg.is_valid());
  2346. int current_line = 1;
  2347. for (String &line : lines) {
  2348. if (uint64_t(line.length()) <= maximum_line_length) {
  2349. TypedArray<RegExMatch> reg_match = reg.search_all(line);
  2350. if (reg_match.size() > 0) {
  2351. found_renames.append(line_formatter(current_line, from.replace("\\.", "."), to, line)); // Without replacing it will print "\.shader" instead ".shader".
  2352. }
  2353. }
  2354. current_line++;
  2355. }
  2356. return found_renames;
  2357. }
  2358. void ProjectConverter3To4::rename_common(const char *array[][2], LocalVector<RegEx *> &cached_regexes, Vector<SourceLine> &source_lines) {
  2359. for (SourceLine &source_line : source_lines) {
  2360. if (source_line.is_comment) {
  2361. continue;
  2362. }
  2363. String &line = source_line.line;
  2364. if (uint64_t(line.length()) <= maximum_line_length) {
  2365. for (unsigned int current_index = 0; current_index < cached_regexes.size(); current_index++) {
  2366. if (line.contains(array[current_index][0])) {
  2367. line = cached_regexes[current_index]->sub(line, array[current_index][1], true);
  2368. }
  2369. }
  2370. }
  2371. }
  2372. }
  2373. Vector<String> ProjectConverter3To4::check_for_rename_common(const char *array[][2], LocalVector<RegEx *> &cached_regexes, Vector<String> &lines) {
  2374. Vector<String> found_renames;
  2375. int current_line = 1;
  2376. for (String &line : lines) {
  2377. if (uint64_t(line.length()) <= maximum_line_length) {
  2378. for (unsigned int current_index = 0; current_index < cached_regexes.size(); current_index++) {
  2379. if (line.contains(array[current_index][0])) {
  2380. TypedArray<RegExMatch> reg_match = cached_regexes[current_index]->search_all(line);
  2381. if (reg_match.size() > 0) {
  2382. found_renames.append(line_formatter(current_line, array[current_index][0], array[current_index][1], line));
  2383. }
  2384. }
  2385. }
  2386. }
  2387. current_line++;
  2388. }
  2389. return found_renames;
  2390. }
  2391. // Prints full info about renamed things e.g.:
  2392. // Line (67) remove -> remove_at - LINE """ doubler._blacklist.remove(0) """
  2393. String ProjectConverter3To4::line_formatter(int current_line, String from, String to, String line) {
  2394. if (from.size() > 200) {
  2395. from = from.substr(0, 197) + "...";
  2396. }
  2397. if (to.size() > 200) {
  2398. to = to.substr(0, 197) + "...";
  2399. }
  2400. if (line.size() > 400) {
  2401. line = line.substr(0, 397) + "...";
  2402. }
  2403. from = from.strip_escapes();
  2404. to = to.strip_escapes();
  2405. line = line.replace("\r", "").replace("\n", "").strip_edges();
  2406. return vformat("Line(%d), %s -> %s - LINE \"\"\" %s \"\"\"", current_line, from, to, line);
  2407. }
  2408. // Prints only full lines e.g.:
  2409. // Line (1) - FULL LINES - """yield(get_tree().create_timer(3), 'timeout')""" =====> """ await get_tree().create_timer(3).timeout """
  2410. String ProjectConverter3To4::simple_line_formatter(int current_line, String old_line, String new_line) {
  2411. if (old_line.size() > 1000) {
  2412. old_line = old_line.substr(0, 997) + "...";
  2413. }
  2414. if (new_line.size() > 1000) {
  2415. new_line = new_line.substr(0, 997) + "...";
  2416. }
  2417. old_line = old_line.replace("\r", "").replace("\n", "").strip_edges();
  2418. new_line = new_line.replace("\r", "").replace("\n", "").strip_edges();
  2419. return vformat("Line (%d) - FULL LINES - \"\"\" %s \"\"\" =====> \"\"\" %s \"\"\"", current_line, old_line, new_line);
  2420. }
  2421. // Collects string from vector strings
  2422. String ProjectConverter3To4::collect_string_from_vector(Vector<SourceLine> &vector) {
  2423. String string = "";
  2424. for (int i = 0; i < vector.size(); i++) {
  2425. string += vector[i].line;
  2426. if (i != vector.size() - 1) {
  2427. string += "\n";
  2428. }
  2429. }
  2430. return string;
  2431. }
  2432. #endif // MODULE_REGEX_ENABLED
  2433. #endif // DISABLE_DEPRECATED