resource_format_text.cpp 62 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238
  1. /*************************************************************************/
  2. /* resource_format_text.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
  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 "resource_format_text.h"
  31. #include "core/config/project_settings.h"
  32. #include "core/io/dir_access.h"
  33. #include "core/io/missing_resource.h"
  34. #include "core/io/resource_format_binary.h"
  35. #include "core/version.h"
  36. // Version 2: changed names for Basis, AABB, Vectors, etc.
  37. // Version 3: new string ID for ext/subresources, breaks forward compat.
  38. #define FORMAT_VERSION 3
  39. #define BINARY_FORMAT_VERSION 4
  40. #include "core/io/dir_access.h"
  41. #include "core/version.h"
  42. #define _printerr() ERR_PRINT(String(res_path + ":" + itos(lines) + " - Parse Error: " + error_text).utf8().get_data());
  43. ///
  44. void ResourceLoaderText::set_local_path(const String &p_local_path) {
  45. res_path = p_local_path;
  46. }
  47. Ref<Resource> ResourceLoaderText::get_resource() {
  48. return resource;
  49. }
  50. Error ResourceLoaderText::_parse_sub_resource_dummy(DummyReadData *p_data, VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str) {
  51. VariantParser::Token token;
  52. VariantParser::get_token(p_stream, token, line, r_err_str);
  53. if (token.type != VariantParser::TK_NUMBER && token.type != VariantParser::TK_STRING) {
  54. r_err_str = "Expected number (old style) or string (sub-resource index)";
  55. return ERR_PARSE_ERROR;
  56. }
  57. if (p_data->no_placeholders) {
  58. r_res.unref();
  59. } else {
  60. String unique_id = token.value;
  61. if (!p_data->resource_map.has(unique_id)) {
  62. r_err_str = "Found unique_id reference before mapping, sub-resources stored out of order in resource file";
  63. return ERR_PARSE_ERROR;
  64. }
  65. r_res = p_data->resource_map[unique_id];
  66. }
  67. VariantParser::get_token(p_stream, token, line, r_err_str);
  68. if (token.type != VariantParser::TK_PARENTHESIS_CLOSE) {
  69. r_err_str = "Expected ')'";
  70. return ERR_PARSE_ERROR;
  71. }
  72. return OK;
  73. }
  74. Error ResourceLoaderText::_parse_ext_resource_dummy(DummyReadData *p_data, VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str) {
  75. VariantParser::Token token;
  76. VariantParser::get_token(p_stream, token, line, r_err_str);
  77. if (token.type != VariantParser::TK_NUMBER && token.type != VariantParser::TK_STRING) {
  78. r_err_str = "Expected number (old style sub-resource index) or String (ext-resource ID)";
  79. return ERR_PARSE_ERROR;
  80. }
  81. if (p_data->no_placeholders) {
  82. r_res.unref();
  83. } else {
  84. String id = token.value;
  85. ERR_FAIL_COND_V(!p_data->rev_external_resources.has(id), ERR_PARSE_ERROR);
  86. r_res = p_data->rev_external_resources[id];
  87. }
  88. VariantParser::get_token(p_stream, token, line, r_err_str);
  89. if (token.type != VariantParser::TK_PARENTHESIS_CLOSE) {
  90. r_err_str = "Expected ')'";
  91. return ERR_PARSE_ERROR;
  92. }
  93. return OK;
  94. }
  95. Error ResourceLoaderText::_parse_sub_resource(VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str) {
  96. VariantParser::Token token;
  97. VariantParser::get_token(p_stream, token, line, r_err_str);
  98. if (token.type != VariantParser::TK_NUMBER && token.type != VariantParser::TK_STRING) {
  99. r_err_str = "Expected number (old style sub-resource index) or string";
  100. return ERR_PARSE_ERROR;
  101. }
  102. String id = token.value;
  103. ERR_FAIL_COND_V(!int_resources.has(id), ERR_INVALID_PARAMETER);
  104. r_res = int_resources[id];
  105. VariantParser::get_token(p_stream, token, line, r_err_str);
  106. if (token.type != VariantParser::TK_PARENTHESIS_CLOSE) {
  107. r_err_str = "Expected ')'";
  108. return ERR_PARSE_ERROR;
  109. }
  110. return OK;
  111. }
  112. Error ResourceLoaderText::_parse_ext_resource(VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str) {
  113. VariantParser::Token token;
  114. VariantParser::get_token(p_stream, token, line, r_err_str);
  115. if (token.type != VariantParser::TK_NUMBER && token.type != VariantParser::TK_STRING) {
  116. r_err_str = "Expected number (old style sub-resource index) or String (ext-resource ID)";
  117. return ERR_PARSE_ERROR;
  118. }
  119. String id = token.value;
  120. if (!ignore_resource_parsing) {
  121. if (!ext_resources.has(id)) {
  122. r_err_str = "Can't load cached ext-resource id: " + id;
  123. return ERR_PARSE_ERROR;
  124. }
  125. String path = ext_resources[id].path;
  126. String type = ext_resources[id].type;
  127. if (ext_resources[id].cache.is_valid()) {
  128. r_res = ext_resources[id].cache;
  129. } else if (use_sub_threads) {
  130. Ref<Resource> res = ResourceLoader::load_threaded_get(path);
  131. if (res.is_null()) {
  132. if (ResourceLoader::get_abort_on_missing_resources()) {
  133. error = ERR_FILE_MISSING_DEPENDENCIES;
  134. error_text = "[ext_resource] referenced nonexistent resource at: " + path;
  135. _printerr();
  136. return error;
  137. } else {
  138. ResourceLoader::notify_dependency_error(local_path, path, type);
  139. }
  140. } else {
  141. ext_resources[id].cache = res;
  142. r_res = res;
  143. }
  144. } else {
  145. error = ERR_FILE_MISSING_DEPENDENCIES;
  146. error_text = "[ext_resource] referenced non-loaded resource at: " + path;
  147. _printerr();
  148. return error;
  149. }
  150. } else {
  151. r_res = Ref<Resource>();
  152. }
  153. VariantParser::get_token(p_stream, token, line, r_err_str);
  154. if (token.type != VariantParser::TK_PARENTHESIS_CLOSE) {
  155. r_err_str = "Expected ')'";
  156. return ERR_PARSE_ERROR;
  157. }
  158. return OK;
  159. }
  160. Ref<PackedScene> ResourceLoaderText::_parse_node_tag(VariantParser::ResourceParser &parser) {
  161. Ref<PackedScene> packed_scene;
  162. packed_scene.instantiate();
  163. while (true) {
  164. if (next_tag.name == "node") {
  165. int parent = -1;
  166. int owner = -1;
  167. int type = -1;
  168. int name = -1;
  169. int instance = -1;
  170. int index = -1;
  171. //int base_scene=-1;
  172. if (next_tag.fields.has("name")) {
  173. name = packed_scene->get_state()->add_name(next_tag.fields["name"]);
  174. }
  175. if (next_tag.fields.has("parent")) {
  176. NodePath np = next_tag.fields["parent"];
  177. np.prepend_period(); //compatible to how it manages paths internally
  178. parent = packed_scene->get_state()->add_node_path(np);
  179. }
  180. if (next_tag.fields.has("type")) {
  181. type = packed_scene->get_state()->add_name(next_tag.fields["type"]);
  182. } else {
  183. type = SceneState::TYPE_INSTANCED; //no type? assume this was instantiated
  184. }
  185. HashSet<StringName> path_properties;
  186. if (next_tag.fields.has("node_paths")) {
  187. Vector<String> paths = next_tag.fields["node_paths"];
  188. for (int i = 0; i < paths.size(); i++) {
  189. path_properties.insert(paths[i]);
  190. }
  191. }
  192. if (next_tag.fields.has("instance")) {
  193. instance = packed_scene->get_state()->add_value(next_tag.fields["instance"]);
  194. if (packed_scene->get_state()->get_node_count() == 0 && parent == -1) {
  195. packed_scene->get_state()->set_base_scene(instance);
  196. instance = -1;
  197. }
  198. }
  199. if (next_tag.fields.has("instance_placeholder")) {
  200. String path = next_tag.fields["instance_placeholder"];
  201. int path_v = packed_scene->get_state()->add_value(path);
  202. if (packed_scene->get_state()->get_node_count() == 0) {
  203. error = ERR_FILE_CORRUPT;
  204. error_text = "Instance Placeholder can't be used for inheritance.";
  205. _printerr();
  206. return Ref<PackedScene>();
  207. }
  208. instance = path_v | SceneState::FLAG_INSTANCE_IS_PLACEHOLDER;
  209. }
  210. if (next_tag.fields.has("owner")) {
  211. owner = packed_scene->get_state()->add_node_path(next_tag.fields["owner"]);
  212. } else {
  213. if (parent != -1 && !(type == SceneState::TYPE_INSTANCED && instance == -1)) {
  214. owner = 0; //if no owner, owner is root
  215. }
  216. }
  217. if (next_tag.fields.has("index")) {
  218. index = next_tag.fields["index"];
  219. }
  220. int node_id = packed_scene->get_state()->add_node(parent, owner, type, name, instance, index);
  221. if (next_tag.fields.has("groups")) {
  222. Array groups = next_tag.fields["groups"];
  223. for (int i = 0; i < groups.size(); i++) {
  224. packed_scene->get_state()->add_node_group(node_id, packed_scene->get_state()->add_name(groups[i]));
  225. }
  226. }
  227. while (true) {
  228. String assign;
  229. Variant value;
  230. error = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, &parser);
  231. if (error) {
  232. if (error == ERR_FILE_MISSING_DEPENDENCIES) {
  233. // Resource loading error, just skip it.
  234. } else if (error != ERR_FILE_EOF) {
  235. _printerr();
  236. return Ref<PackedScene>();
  237. } else {
  238. error = OK;
  239. return packed_scene;
  240. }
  241. }
  242. if (!assign.is_empty()) {
  243. StringName assign_name = assign;
  244. int nameidx = packed_scene->get_state()->add_name(assign_name);
  245. int valueidx = packed_scene->get_state()->add_value(value);
  246. packed_scene->get_state()->add_node_property(node_id, nameidx, valueidx, path_properties.has(assign_name));
  247. //it's assignment
  248. } else if (!next_tag.name.is_empty()) {
  249. break;
  250. }
  251. }
  252. } else if (next_tag.name == "connection") {
  253. if (!next_tag.fields.has("from")) {
  254. error = ERR_FILE_CORRUPT;
  255. error_text = "missing 'from' field from connection tag";
  256. return Ref<PackedScene>();
  257. }
  258. if (!next_tag.fields.has("to")) {
  259. error = ERR_FILE_CORRUPT;
  260. error_text = "missing 'to' field from connection tag";
  261. return Ref<PackedScene>();
  262. }
  263. if (!next_tag.fields.has("signal")) {
  264. error = ERR_FILE_CORRUPT;
  265. error_text = "missing 'signal' field from connection tag";
  266. return Ref<PackedScene>();
  267. }
  268. if (!next_tag.fields.has("method")) {
  269. error = ERR_FILE_CORRUPT;
  270. error_text = "missing 'method' field from connection tag";
  271. return Ref<PackedScene>();
  272. }
  273. NodePath from = next_tag.fields["from"];
  274. NodePath to = next_tag.fields["to"];
  275. StringName method = next_tag.fields["method"];
  276. StringName signal = next_tag.fields["signal"];
  277. int flags = Object::CONNECT_PERSIST;
  278. int unbinds = 0;
  279. Array binds;
  280. if (next_tag.fields.has("flags")) {
  281. flags = next_tag.fields["flags"];
  282. }
  283. if (next_tag.fields.has("binds")) {
  284. binds = next_tag.fields["binds"];
  285. }
  286. if (next_tag.fields.has("unbinds")) {
  287. unbinds = next_tag.fields["unbinds"];
  288. }
  289. Vector<int> bind_ints;
  290. for (int i = 0; i < binds.size(); i++) {
  291. bind_ints.push_back(packed_scene->get_state()->add_value(binds[i]));
  292. }
  293. packed_scene->get_state()->add_connection(
  294. packed_scene->get_state()->add_node_path(from.simplified()),
  295. packed_scene->get_state()->add_node_path(to.simplified()),
  296. packed_scene->get_state()->add_name(signal),
  297. packed_scene->get_state()->add_name(method),
  298. flags,
  299. unbinds,
  300. bind_ints);
  301. error = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &parser);
  302. if (error) {
  303. if (error != ERR_FILE_EOF) {
  304. _printerr();
  305. return Ref<PackedScene>();
  306. } else {
  307. error = OK;
  308. return packed_scene;
  309. }
  310. }
  311. } else if (next_tag.name == "editable") {
  312. if (!next_tag.fields.has("path")) {
  313. error = ERR_FILE_CORRUPT;
  314. error_text = "missing 'path' field from editable tag";
  315. _printerr();
  316. return Ref<PackedScene>();
  317. }
  318. NodePath path = next_tag.fields["path"];
  319. packed_scene->get_state()->add_editable_instance(path.simplified());
  320. error = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &parser);
  321. if (error) {
  322. if (error != ERR_FILE_EOF) {
  323. _printerr();
  324. return Ref<PackedScene>();
  325. } else {
  326. error = OK;
  327. return packed_scene;
  328. }
  329. }
  330. } else {
  331. error = ERR_FILE_CORRUPT;
  332. _printerr();
  333. return Ref<PackedScene>();
  334. }
  335. }
  336. }
  337. Error ResourceLoaderText::load() {
  338. if (error != OK) {
  339. return error;
  340. }
  341. while (true) {
  342. if (next_tag.name != "ext_resource") {
  343. break;
  344. }
  345. if (!next_tag.fields.has("path")) {
  346. error = ERR_FILE_CORRUPT;
  347. error_text = "Missing 'path' in external resource tag";
  348. _printerr();
  349. return error;
  350. }
  351. if (!next_tag.fields.has("type")) {
  352. error = ERR_FILE_CORRUPT;
  353. error_text = "Missing 'type' in external resource tag";
  354. _printerr();
  355. return error;
  356. }
  357. if (!next_tag.fields.has("id")) {
  358. error = ERR_FILE_CORRUPT;
  359. error_text = "Missing 'id' in external resource tag";
  360. _printerr();
  361. return error;
  362. }
  363. String path = next_tag.fields["path"];
  364. String type = next_tag.fields["type"];
  365. String id = next_tag.fields["id"];
  366. if (next_tag.fields.has("uid")) {
  367. String uidt = next_tag.fields["uid"];
  368. ResourceUID::ID uid = ResourceUID::get_singleton()->text_to_id(uidt);
  369. if (uid != ResourceUID::INVALID_ID && ResourceUID::get_singleton()->has_id(uid)) {
  370. // If a UID is found and the path is valid, it will be used, otherwise, it falls back to the path.
  371. path = ResourceUID::get_singleton()->get_id_path(uid);
  372. } else {
  373. WARN_PRINT(String(res_path + ":" + itos(lines) + " - ext_resource, invalid UUID: " + uidt + " - using text path instead: " + path).utf8().get_data());
  374. }
  375. }
  376. if (!path.contains("://") && path.is_relative_path()) {
  377. // path is relative to file being loaded, so convert to a resource path
  378. path = ProjectSettings::get_singleton()->localize_path(local_path.get_base_dir().path_join(path));
  379. }
  380. if (remaps.has(path)) {
  381. path = remaps[path];
  382. }
  383. ExtResource er;
  384. er.path = path;
  385. er.type = type;
  386. if (use_sub_threads) {
  387. Error err = ResourceLoader::load_threaded_request(path, type, use_sub_threads, ResourceFormatLoader::CACHE_MODE_REUSE, local_path);
  388. if (err != OK) {
  389. if (ResourceLoader::get_abort_on_missing_resources()) {
  390. error = ERR_FILE_CORRUPT;
  391. error_text = "[ext_resource] referenced broken resource at: " + path;
  392. _printerr();
  393. return error;
  394. } else {
  395. ResourceLoader::notify_dependency_error(local_path, path, type);
  396. }
  397. }
  398. } else {
  399. Ref<Resource> res = ResourceLoader::load(path, type);
  400. if (res.is_null()) {
  401. if (ResourceLoader::get_abort_on_missing_resources()) {
  402. error = ERR_FILE_CORRUPT;
  403. error_text = "[ext_resource] referenced nonexistent resource at: " + path;
  404. _printerr();
  405. return error;
  406. } else {
  407. ResourceLoader::notify_dependency_error(local_path, path, type);
  408. }
  409. } else {
  410. #ifdef TOOLS_ENABLED
  411. //remember ID for saving
  412. res->set_id_for_path(local_path, id);
  413. #endif
  414. }
  415. er.cache = res;
  416. }
  417. ext_resources[id] = er;
  418. error = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &rp);
  419. if (error) {
  420. _printerr();
  421. }
  422. resource_current++;
  423. }
  424. //these are the ones that count
  425. resources_total -= resource_current;
  426. resource_current = 0;
  427. while (true) {
  428. if (next_tag.name != "sub_resource") {
  429. break;
  430. }
  431. if (!next_tag.fields.has("type")) {
  432. error = ERR_FILE_CORRUPT;
  433. error_text = "Missing 'type' in external resource tag";
  434. _printerr();
  435. return error;
  436. }
  437. if (!next_tag.fields.has("id")) {
  438. error = ERR_FILE_CORRUPT;
  439. error_text = "Missing 'id' in external resource tag";
  440. _printerr();
  441. return error;
  442. }
  443. String type = next_tag.fields["type"];
  444. String id = next_tag.fields["id"];
  445. String path = local_path + "::" + id;
  446. //bool exists=ResourceCache::has(path);
  447. Ref<Resource> res;
  448. bool do_assign = false;
  449. if (cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE && ResourceCache::has(path)) {
  450. //reuse existing
  451. Ref<Resource> cache = ResourceCache::get_ref(path);
  452. if (cache.is_valid() && cache->get_class() == type) {
  453. res = cache;
  454. res->reset_state();
  455. do_assign = true;
  456. }
  457. }
  458. MissingResource *missing_resource = nullptr;
  459. if (res.is_null()) { //not reuse
  460. Ref<Resource> cache = ResourceCache::get_ref(path);
  461. if (cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE && cache.is_valid()) { //only if it doesn't exist
  462. //cached, do not assign
  463. res = cache;
  464. } else {
  465. //create
  466. Object *obj = ClassDB::instantiate(type);
  467. if (!obj) {
  468. if (ResourceLoader::is_creating_missing_resources_if_class_unavailable_enabled()) {
  469. missing_resource = memnew(MissingResource);
  470. missing_resource->set_original_class(type);
  471. missing_resource->set_recording_properties(true);
  472. obj = missing_resource;
  473. } else {
  474. error_text += "Can't create sub resource of type: " + type;
  475. _printerr();
  476. error = ERR_FILE_CORRUPT;
  477. return error;
  478. }
  479. }
  480. Resource *r = Object::cast_to<Resource>(obj);
  481. if (!r) {
  482. error_text += "Can't create sub resource of type, because not a resource: " + type;
  483. _printerr();
  484. error = ERR_FILE_CORRUPT;
  485. return error;
  486. }
  487. res = Ref<Resource>(r);
  488. do_assign = true;
  489. }
  490. }
  491. resource_current++;
  492. int_resources[id] = res; //always assign int resources
  493. if (do_assign && cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) {
  494. res->set_path(path, cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE);
  495. res->set_scene_unique_id(id);
  496. }
  497. Dictionary missing_resource_properties;
  498. while (true) {
  499. String assign;
  500. Variant value;
  501. error = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, &rp);
  502. if (error) {
  503. _printerr();
  504. return error;
  505. }
  506. if (!assign.is_empty()) {
  507. if (do_assign) {
  508. bool set_valid = true;
  509. if (value.get_type() == Variant::OBJECT && missing_resource != nullptr) {
  510. // If the property being set is a missing resource (and the parent is not),
  511. // then setting it will most likely not work.
  512. // Instead, save it as metadata.
  513. Ref<MissingResource> mr = value;
  514. if (mr.is_valid()) {
  515. missing_resource_properties[assign] = mr;
  516. set_valid = false;
  517. }
  518. }
  519. if (set_valid) {
  520. res->set(assign, value);
  521. }
  522. }
  523. //it's assignment
  524. } else if (!next_tag.name.is_empty()) {
  525. error = OK;
  526. break;
  527. } else {
  528. error = ERR_FILE_CORRUPT;
  529. error_text = "Premature end of file while parsing [sub_resource]";
  530. _printerr();
  531. return error;
  532. }
  533. }
  534. if (missing_resource) {
  535. missing_resource->set_recording_properties(false);
  536. }
  537. if (!missing_resource_properties.is_empty()) {
  538. res->set_meta(META_MISSING_RESOURCES, missing_resource_properties);
  539. }
  540. if (progress && resources_total > 0) {
  541. *progress = resource_current / float(resources_total);
  542. }
  543. }
  544. while (true) {
  545. if (next_tag.name != "resource") {
  546. break;
  547. }
  548. if (is_scene) {
  549. error_text += "found the 'resource' tag on a scene file!";
  550. _printerr();
  551. error = ERR_FILE_CORRUPT;
  552. return error;
  553. }
  554. Ref<Resource> cache = ResourceCache::get_ref(local_path);
  555. if (cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE && cache.is_valid() && cache->get_class() == res_type) {
  556. cache->reset_state();
  557. resource = cache;
  558. }
  559. MissingResource *missing_resource = nullptr;
  560. if (!resource.is_valid()) {
  561. Object *obj = ClassDB::instantiate(res_type);
  562. if (!obj) {
  563. if (ResourceLoader::is_creating_missing_resources_if_class_unavailable_enabled()) {
  564. missing_resource = memnew(MissingResource);
  565. missing_resource->set_original_class(res_type);
  566. missing_resource->set_recording_properties(true);
  567. obj = missing_resource;
  568. } else {
  569. error_text += "Can't create sub resource of type: " + res_type;
  570. _printerr();
  571. error = ERR_FILE_CORRUPT;
  572. return error;
  573. }
  574. }
  575. Resource *r = Object::cast_to<Resource>(obj);
  576. if (!r) {
  577. error_text += "Can't create sub resource of type, because not a resource: " + res_type;
  578. _printerr();
  579. error = ERR_FILE_CORRUPT;
  580. return error;
  581. }
  582. resource = Ref<Resource>(r);
  583. }
  584. resource_current++;
  585. Dictionary missing_resource_properties;
  586. while (true) {
  587. String assign;
  588. Variant value;
  589. error = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, &rp);
  590. if (error) {
  591. if (error != ERR_FILE_EOF) {
  592. _printerr();
  593. } else {
  594. error = OK;
  595. if (cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) {
  596. if (!ResourceCache::has(res_path)) {
  597. resource->set_path(res_path);
  598. }
  599. resource->set_as_translation_remapped(translation_remapped);
  600. }
  601. }
  602. return error;
  603. }
  604. if (!assign.is_empty()) {
  605. bool set_valid = true;
  606. if (value.get_type() == Variant::OBJECT && missing_resource != nullptr) {
  607. // If the property being set is a missing resource (and the parent is not),
  608. // then setting it will most likely not work.
  609. // Instead, save it as metadata.
  610. Ref<MissingResource> mr = value;
  611. if (mr.is_valid()) {
  612. missing_resource_properties[assign] = mr;
  613. set_valid = false;
  614. }
  615. }
  616. if (set_valid) {
  617. resource->set(assign, value);
  618. }
  619. //it's assignment
  620. } else if (!next_tag.name.is_empty()) {
  621. error = ERR_FILE_CORRUPT;
  622. error_text = "Extra tag found when parsing main resource file";
  623. _printerr();
  624. return error;
  625. } else {
  626. break;
  627. }
  628. }
  629. if (missing_resource) {
  630. missing_resource->set_recording_properties(false);
  631. }
  632. if (!missing_resource_properties.is_empty()) {
  633. resource->set_meta(META_MISSING_RESOURCES, missing_resource_properties);
  634. }
  635. error = OK;
  636. if (progress && resources_total > 0) {
  637. *progress = resource_current / float(resources_total);
  638. }
  639. return error;
  640. }
  641. //for scene files
  642. if (next_tag.name == "node") {
  643. if (!is_scene) {
  644. error_text += "found the 'node' tag on a resource file!";
  645. _printerr();
  646. error = ERR_FILE_CORRUPT;
  647. return error;
  648. }
  649. Ref<PackedScene> packed_scene = _parse_node_tag(rp);
  650. if (!packed_scene.is_valid()) {
  651. return error;
  652. }
  653. error = OK;
  654. //get it here
  655. resource = packed_scene;
  656. if (cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE && !ResourceCache::has(res_path)) {
  657. packed_scene->set_path(res_path);
  658. }
  659. resource_current++;
  660. if (progress && resources_total > 0) {
  661. *progress = resource_current / float(resources_total);
  662. }
  663. return error;
  664. } else {
  665. error_text += "Unknown tag in file: " + next_tag.name;
  666. _printerr();
  667. error = ERR_FILE_CORRUPT;
  668. return error;
  669. }
  670. }
  671. int ResourceLoaderText::get_stage() const {
  672. return resource_current;
  673. }
  674. int ResourceLoaderText::get_stage_count() const {
  675. return resources_total; //+ext_resources;
  676. }
  677. void ResourceLoaderText::set_translation_remapped(bool p_remapped) {
  678. translation_remapped = p_remapped;
  679. }
  680. ResourceLoaderText::ResourceLoaderText() {}
  681. void ResourceLoaderText::get_dependencies(Ref<FileAccess> p_f, List<String> *p_dependencies, bool p_add_types) {
  682. open(p_f);
  683. ignore_resource_parsing = true;
  684. ERR_FAIL_COND(error != OK);
  685. while (next_tag.name == "ext_resource") {
  686. if (!next_tag.fields.has("type")) {
  687. error = ERR_FILE_CORRUPT;
  688. error_text = "Missing 'type' in external resource tag";
  689. _printerr();
  690. return;
  691. }
  692. if (!next_tag.fields.has("id")) {
  693. error = ERR_FILE_CORRUPT;
  694. error_text = "Missing 'id' in external resource tag";
  695. _printerr();
  696. return;
  697. }
  698. String path = next_tag.fields["path"];
  699. String type = next_tag.fields["type"];
  700. bool using_uid = false;
  701. if (next_tag.fields.has("uid")) {
  702. //if uid exists, return uid in text format, not the path
  703. String uidt = next_tag.fields["uid"];
  704. ResourceUID::ID uid = ResourceUID::get_singleton()->text_to_id(uidt);
  705. if (uid != ResourceUID::INVALID_ID) {
  706. path = ResourceUID::get_singleton()->id_to_text(uid);
  707. using_uid = true;
  708. }
  709. }
  710. if (!using_uid && !path.contains("://") && path.is_relative_path()) {
  711. // path is relative to file being loaded, so convert to a resource path
  712. path = ProjectSettings::get_singleton()->localize_path(local_path.get_base_dir().path_join(path));
  713. }
  714. if (p_add_types) {
  715. path += "::" + type;
  716. }
  717. p_dependencies->push_back(path);
  718. Error err = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &rp);
  719. if (err) {
  720. print_line(error_text + " - " + itos(lines));
  721. error_text = "Unexpected end of file";
  722. _printerr();
  723. error = ERR_FILE_CORRUPT;
  724. }
  725. }
  726. }
  727. Error ResourceLoaderText::rename_dependencies(Ref<FileAccess> p_f, const String &p_path, const HashMap<String, String> &p_map) {
  728. open(p_f, true);
  729. ERR_FAIL_COND_V(error != OK, error);
  730. ignore_resource_parsing = true;
  731. //FileAccess
  732. Ref<FileAccess> fw;
  733. String base_path = local_path.get_base_dir();
  734. uint64_t tag_end = f->get_position();
  735. while (true) {
  736. Error err = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &rp);
  737. if (err != OK) {
  738. error = ERR_FILE_CORRUPT;
  739. ERR_FAIL_V(error);
  740. }
  741. if (next_tag.name != "ext_resource") {
  742. //nothing was done
  743. if (fw.is_null()) {
  744. return OK;
  745. }
  746. break;
  747. } else {
  748. if (fw.is_null()) {
  749. fw = FileAccess::open(p_path + ".depren", FileAccess::WRITE);
  750. if (is_scene) {
  751. fw->store_line("[gd_scene load_steps=" + itos(resources_total) + " format=" + itos(FORMAT_VERSION) + "]\n");
  752. } else {
  753. fw->store_line("[gd_resource type=\"" + res_type + "\" load_steps=" + itos(resources_total) + " format=" + itos(FORMAT_VERSION) + "]\n");
  754. }
  755. }
  756. if (!next_tag.fields.has("path") || !next_tag.fields.has("id") || !next_tag.fields.has("type")) {
  757. error = ERR_FILE_CORRUPT;
  758. ERR_FAIL_V(error);
  759. }
  760. String path = next_tag.fields["path"];
  761. String id = next_tag.fields["id"];
  762. String type = next_tag.fields["type"];
  763. if (next_tag.fields.has("uid")) {
  764. String uidt = next_tag.fields["uid"];
  765. ResourceUID::ID uid = ResourceUID::get_singleton()->text_to_id(uidt);
  766. if (uid != ResourceUID::INVALID_ID && ResourceUID::get_singleton()->has_id(uid)) {
  767. // If a UID is found and the path is valid, it will be used, otherwise, it falls back to the path.
  768. path = ResourceUID::get_singleton()->get_id_path(uid);
  769. }
  770. }
  771. bool relative = false;
  772. if (!path.begins_with("res://")) {
  773. path = base_path.path_join(path).simplify_path();
  774. relative = true;
  775. }
  776. if (p_map.has(path)) {
  777. String np = p_map[path];
  778. path = np;
  779. }
  780. if (relative) {
  781. //restore relative
  782. path = base_path.path_to_file(path);
  783. }
  784. String s = "[ext_resource type=\"" + type + "\"";
  785. ResourceUID::ID uid = ResourceSaver::get_resource_id_for_path(path);
  786. if (uid != ResourceUID::INVALID_ID) {
  787. s += " uid=\"" + ResourceUID::get_singleton()->id_to_text(uid) + "\"";
  788. }
  789. s += " path=\"" + path + "\" id=\"" + id + "\"]";
  790. fw->store_line(s); // Bundled.
  791. tag_end = f->get_position();
  792. }
  793. }
  794. f->seek(tag_end);
  795. uint8_t c = f->get_8();
  796. if (c == '\n' && !f->eof_reached()) {
  797. // Skip first newline character since we added one
  798. c = f->get_8();
  799. }
  800. while (!f->eof_reached()) {
  801. fw->store_8(c);
  802. c = f->get_8();
  803. }
  804. bool all_ok = fw->get_error() == OK;
  805. if (!all_ok) {
  806. return ERR_CANT_CREATE;
  807. }
  808. return OK;
  809. }
  810. void ResourceLoaderText::open(Ref<FileAccess> p_f, bool p_skip_first_tag) {
  811. error = OK;
  812. lines = 1;
  813. f = p_f;
  814. stream.f = f;
  815. is_scene = false;
  816. ignore_resource_parsing = false;
  817. resource_current = 0;
  818. VariantParser::Tag tag;
  819. Error err = VariantParser::parse_tag(&stream, lines, error_text, tag);
  820. if (err) {
  821. error = err;
  822. _printerr();
  823. return;
  824. }
  825. if (tag.fields.has("format")) {
  826. int fmt = tag.fields["format"];
  827. if (fmt > FORMAT_VERSION) {
  828. error_text = "Saved with newer format version";
  829. _printerr();
  830. error = ERR_PARSE_ERROR;
  831. return;
  832. }
  833. }
  834. if (tag.name == "gd_scene") {
  835. is_scene = true;
  836. } else if (tag.name == "gd_resource") {
  837. if (!tag.fields.has("type")) {
  838. error_text = "Missing 'type' field in 'gd_resource' tag";
  839. _printerr();
  840. error = ERR_PARSE_ERROR;
  841. return;
  842. }
  843. res_type = tag.fields["type"];
  844. } else {
  845. error_text = "Unrecognized file type: " + tag.name;
  846. _printerr();
  847. error = ERR_PARSE_ERROR;
  848. return;
  849. }
  850. if (tag.fields.has("uid")) {
  851. res_uid = ResourceUID::get_singleton()->text_to_id(tag.fields["uid"]);
  852. } else {
  853. res_uid = ResourceUID::INVALID_ID;
  854. }
  855. if (tag.fields.has("load_steps")) {
  856. resources_total = tag.fields["load_steps"];
  857. } else {
  858. resources_total = 0;
  859. }
  860. if (!p_skip_first_tag) {
  861. err = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &rp);
  862. if (err) {
  863. error_text = "Unexpected end of file";
  864. _printerr();
  865. error = ERR_FILE_CORRUPT;
  866. }
  867. }
  868. rp.ext_func = _parse_ext_resources;
  869. rp.sub_func = _parse_sub_resources;
  870. rp.userdata = this;
  871. }
  872. static void bs_save_unicode_string(Ref<FileAccess> p_f, const String &p_string, bool p_bit_on_len = false) {
  873. CharString utf8 = p_string.utf8();
  874. if (p_bit_on_len) {
  875. p_f->store_32((utf8.length() + 1) | 0x80000000);
  876. } else {
  877. p_f->store_32(utf8.length() + 1);
  878. }
  879. p_f->store_buffer((const uint8_t *)utf8.get_data(), utf8.length() + 1);
  880. }
  881. Error ResourceLoaderText::save_as_binary(const String &p_path) {
  882. if (error) {
  883. return error;
  884. }
  885. Ref<FileAccess> wf = FileAccess::open(p_path, FileAccess::WRITE);
  886. if (wf.is_null()) {
  887. return ERR_CANT_OPEN;
  888. }
  889. //save header compressed
  890. static const uint8_t header[4] = { 'R', 'S', 'R', 'C' };
  891. wf->store_buffer(header, 4);
  892. wf->store_32(0); //endianness, little endian
  893. wf->store_32(0); //64 bits file, false for now
  894. wf->store_32(VERSION_MAJOR);
  895. wf->store_32(VERSION_MINOR);
  896. static const int save_format_version = BINARY_FORMAT_VERSION;
  897. wf->store_32(save_format_version);
  898. bs_save_unicode_string(wf, is_scene ? "PackedScene" : resource_type);
  899. wf->store_64(0); //offset to import metadata, this is no longer used
  900. wf->store_32(ResourceFormatSaverBinaryInstance::FORMAT_FLAG_NAMED_SCENE_IDS | ResourceFormatSaverBinaryInstance::FORMAT_FLAG_UIDS);
  901. wf->store_64(res_uid);
  902. for (int i = 0; i < ResourceFormatSaverBinaryInstance::RESERVED_FIELDS; i++) {
  903. wf->store_32(0); // reserved
  904. }
  905. wf->store_32(0); //string table size, will not be in use
  906. uint64_t ext_res_count_pos = wf->get_position();
  907. wf->store_32(0); //zero ext resources, still parsing them
  908. //go with external resources
  909. DummyReadData dummy_read;
  910. VariantParser::ResourceParser rp;
  911. rp.ext_func = _parse_ext_resource_dummys;
  912. rp.sub_func = _parse_sub_resource_dummys;
  913. rp.userdata = &dummy_read;
  914. while (next_tag.name == "ext_resource") {
  915. if (!next_tag.fields.has("path")) {
  916. error = ERR_FILE_CORRUPT;
  917. error_text = "Missing 'path' in external resource tag";
  918. _printerr();
  919. return error;
  920. }
  921. if (!next_tag.fields.has("type")) {
  922. error = ERR_FILE_CORRUPT;
  923. error_text = "Missing 'type' in external resource tag";
  924. _printerr();
  925. return error;
  926. }
  927. if (!next_tag.fields.has("id")) {
  928. error = ERR_FILE_CORRUPT;
  929. error_text = "Missing 'id' in external resource tag";
  930. _printerr();
  931. return error;
  932. }
  933. String path = next_tag.fields["path"];
  934. String type = next_tag.fields["type"];
  935. String id = next_tag.fields["id"];
  936. ResourceUID::ID uid = ResourceUID::INVALID_ID;
  937. if (next_tag.fields.has("uid")) {
  938. String uidt = next_tag.fields["uid"];
  939. uid = ResourceUID::get_singleton()->text_to_id(uidt);
  940. }
  941. bs_save_unicode_string(wf, type);
  942. bs_save_unicode_string(wf, path);
  943. wf->store_64(uid);
  944. int lindex = dummy_read.external_resources.size();
  945. Ref<DummyResource> dr;
  946. dr.instantiate();
  947. dr->set_path("res://dummy" + itos(lindex)); //anything is good to detect it for saving as external
  948. dummy_read.external_resources[dr] = lindex;
  949. dummy_read.rev_external_resources[id] = dr;
  950. error = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &rp);
  951. if (error) {
  952. _printerr();
  953. return error;
  954. }
  955. }
  956. // save external resource table
  957. wf->seek(ext_res_count_pos);
  958. wf->store_32(dummy_read.external_resources.size());
  959. wf->seek_end();
  960. //now, save resources to a separate file, for now
  961. uint64_t sub_res_count_pos = wf->get_position();
  962. wf->store_32(0); //zero sub resources, still parsing them
  963. String temp_file = p_path + ".temp";
  964. Vector<uint64_t> local_offsets;
  965. Vector<uint64_t> local_pointers_pos;
  966. {
  967. Ref<FileAccess> wf2 = FileAccess::open(temp_file, FileAccess::WRITE);
  968. if (wf2.is_null()) {
  969. return ERR_CANT_OPEN;
  970. }
  971. while (next_tag.name == "sub_resource" || next_tag.name == "resource") {
  972. String type;
  973. String id;
  974. bool main_res;
  975. if (next_tag.name == "sub_resource") {
  976. if (!next_tag.fields.has("type")) {
  977. error = ERR_FILE_CORRUPT;
  978. error_text = "Missing 'type' in external resource tag";
  979. _printerr();
  980. return error;
  981. }
  982. if (!next_tag.fields.has("id")) {
  983. error = ERR_FILE_CORRUPT;
  984. error_text = "Missing 'id' in external resource tag";
  985. _printerr();
  986. return error;
  987. }
  988. type = next_tag.fields["type"];
  989. id = next_tag.fields["id"];
  990. main_res = false;
  991. if (!dummy_read.resource_map.has(id)) {
  992. Ref<DummyResource> dr;
  993. dr.instantiate();
  994. dr->set_scene_unique_id(id);
  995. dummy_read.resource_map[id] = dr;
  996. uint32_t im_size = dummy_read.resource_index_map.size();
  997. dummy_read.resource_index_map.insert(dr, im_size);
  998. }
  999. } else {
  1000. type = res_type;
  1001. String uid_text = ResourceUID::get_singleton()->id_to_text(res_uid);
  1002. id = type + "_" + uid_text.replace("uid://", "").replace("<invalid>", "0");
  1003. main_res = true;
  1004. }
  1005. local_offsets.push_back(wf2->get_position());
  1006. bs_save_unicode_string(wf, "local://" + id);
  1007. local_pointers_pos.push_back(wf->get_position());
  1008. wf->store_64(0); //temp local offset
  1009. bs_save_unicode_string(wf2, type);
  1010. uint64_t propcount_ofs = wf2->get_position();
  1011. wf2->store_32(0);
  1012. int prop_count = 0;
  1013. while (true) {
  1014. String assign;
  1015. Variant value;
  1016. error = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, &rp);
  1017. if (error) {
  1018. if (main_res && error == ERR_FILE_EOF) {
  1019. next_tag.name = ""; //exit
  1020. break;
  1021. }
  1022. _printerr();
  1023. return error;
  1024. }
  1025. if (!assign.is_empty()) {
  1026. HashMap<StringName, int> empty_string_map; //unused
  1027. bs_save_unicode_string(wf2, assign, true);
  1028. ResourceFormatSaverBinaryInstance::write_variant(wf2, value, dummy_read.resource_index_map, dummy_read.external_resources, empty_string_map);
  1029. prop_count++;
  1030. } else if (!next_tag.name.is_empty()) {
  1031. error = OK;
  1032. break;
  1033. } else {
  1034. error = ERR_FILE_CORRUPT;
  1035. error_text = "Premature end of file while parsing [sub_resource]";
  1036. _printerr();
  1037. return error;
  1038. }
  1039. }
  1040. wf2->seek(propcount_ofs);
  1041. wf2->store_32(prop_count);
  1042. wf2->seek_end();
  1043. }
  1044. if (next_tag.name == "node") {
  1045. // This is a node, must save one more!
  1046. if (!is_scene) {
  1047. error_text += "found the 'node' tag on a resource file!";
  1048. _printerr();
  1049. error = ERR_FILE_CORRUPT;
  1050. return error;
  1051. }
  1052. Ref<PackedScene> packed_scene = _parse_node_tag(rp);
  1053. if (!packed_scene.is_valid()) {
  1054. return error;
  1055. }
  1056. error = OK;
  1057. //get it here
  1058. List<PropertyInfo> props;
  1059. packed_scene->get_property_list(&props);
  1060. String id = "PackedScene_" + ResourceUID::get_singleton()->id_to_text(res_uid).replace("uid://", "").replace("<invalid>", "0");
  1061. bs_save_unicode_string(wf, "local://" + id);
  1062. local_pointers_pos.push_back(wf->get_position());
  1063. wf->store_64(0); //temp local offset
  1064. local_offsets.push_back(wf2->get_position());
  1065. bs_save_unicode_string(wf2, "PackedScene");
  1066. uint64_t propcount_ofs = wf2->get_position();
  1067. wf2->store_32(0);
  1068. int prop_count = 0;
  1069. for (const PropertyInfo &E : props) {
  1070. if (!(E.usage & PROPERTY_USAGE_STORAGE)) {
  1071. continue;
  1072. }
  1073. String name = E.name;
  1074. Variant value = packed_scene->get(name);
  1075. HashMap<StringName, int> empty_string_map; //unused
  1076. bs_save_unicode_string(wf2, name, true);
  1077. ResourceFormatSaverBinaryInstance::write_variant(wf2, value, dummy_read.resource_index_map, dummy_read.external_resources, empty_string_map);
  1078. prop_count++;
  1079. }
  1080. wf2->seek(propcount_ofs);
  1081. wf2->store_32(prop_count);
  1082. wf2->seek_end();
  1083. }
  1084. }
  1085. uint64_t offset_from = wf->get_position();
  1086. wf->seek(sub_res_count_pos); //plus one because the saved one
  1087. wf->store_32(local_offsets.size());
  1088. for (int i = 0; i < local_offsets.size(); i++) {
  1089. wf->seek(local_pointers_pos[i]);
  1090. wf->store_64(local_offsets[i] + offset_from);
  1091. }
  1092. wf->seek_end();
  1093. Vector<uint8_t> data = FileAccess::get_file_as_array(temp_file);
  1094. wf->store_buffer(data.ptr(), data.size());
  1095. {
  1096. Ref<DirAccess> dar = DirAccess::open(temp_file.get_base_dir());
  1097. dar->remove(temp_file);
  1098. }
  1099. wf->store_buffer((const uint8_t *)"RSRC", 4); //magic at end
  1100. return OK;
  1101. }
  1102. Error ResourceLoaderText::get_classes_used(HashSet<StringName> *r_classes) {
  1103. if (error) {
  1104. return error;
  1105. }
  1106. ignore_resource_parsing = true;
  1107. DummyReadData dummy_read;
  1108. dummy_read.no_placeholders = true;
  1109. VariantParser::ResourceParser rp;
  1110. rp.ext_func = _parse_ext_resource_dummys;
  1111. rp.sub_func = _parse_sub_resource_dummys;
  1112. rp.userdata = &dummy_read;
  1113. while (next_tag.name == "ext_resource") {
  1114. error = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &rp);
  1115. if (error) {
  1116. _printerr();
  1117. return error;
  1118. }
  1119. }
  1120. while (next_tag.name == "sub_resource" || next_tag.name == "resource") {
  1121. if (next_tag.name == "sub_resource") {
  1122. if (!next_tag.fields.has("type")) {
  1123. error = ERR_FILE_CORRUPT;
  1124. error_text = "Missing 'type' in external resource tag";
  1125. _printerr();
  1126. return error;
  1127. }
  1128. r_classes->insert(next_tag.fields["type"]);
  1129. } else {
  1130. r_classes->insert(next_tag.fields["res_type"]);
  1131. }
  1132. while (true) {
  1133. String assign;
  1134. Variant value;
  1135. error = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, &rp);
  1136. if (error) {
  1137. if (error == ERR_FILE_EOF) {
  1138. return OK;
  1139. }
  1140. _printerr();
  1141. return error;
  1142. }
  1143. if (!assign.is_empty()) {
  1144. continue;
  1145. } else if (!next_tag.name.is_empty()) {
  1146. error = OK;
  1147. break;
  1148. } else {
  1149. error = ERR_FILE_CORRUPT;
  1150. error_text = "Premature end of file while parsing [sub_resource]";
  1151. _printerr();
  1152. return error;
  1153. }
  1154. }
  1155. }
  1156. while (next_tag.name == "node") {
  1157. // This is a node, must save one more!
  1158. if (!is_scene) {
  1159. error_text += "found the 'node' tag on a resource file!";
  1160. _printerr();
  1161. error = ERR_FILE_CORRUPT;
  1162. return error;
  1163. }
  1164. if (!next_tag.fields.has("type")) {
  1165. error = ERR_FILE_CORRUPT;
  1166. error_text = "Missing 'type' in external resource tag";
  1167. _printerr();
  1168. return error;
  1169. }
  1170. r_classes->insert(next_tag.fields["type"]);
  1171. while (true) {
  1172. String assign;
  1173. Variant value;
  1174. error = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, &rp);
  1175. if (error) {
  1176. if (error == ERR_FILE_MISSING_DEPENDENCIES) {
  1177. // Resource loading error, just skip it.
  1178. } else if (error != ERR_FILE_EOF) {
  1179. _printerr();
  1180. return error;
  1181. } else {
  1182. return OK;
  1183. }
  1184. }
  1185. if (!assign.is_empty()) {
  1186. continue;
  1187. } else if (!next_tag.name.is_empty()) {
  1188. error = OK;
  1189. break;
  1190. } else {
  1191. error = ERR_FILE_CORRUPT;
  1192. error_text = "Premature end of file while parsing [sub_resource]";
  1193. _printerr();
  1194. return error;
  1195. }
  1196. }
  1197. }
  1198. return OK;
  1199. }
  1200. String ResourceLoaderText::recognize(Ref<FileAccess> p_f) {
  1201. error = OK;
  1202. lines = 1;
  1203. f = p_f;
  1204. stream.f = f;
  1205. ignore_resource_parsing = true;
  1206. VariantParser::Tag tag;
  1207. Error err = VariantParser::parse_tag(&stream, lines, error_text, tag);
  1208. if (err) {
  1209. _printerr();
  1210. return "";
  1211. }
  1212. if (tag.fields.has("format")) {
  1213. int fmt = tag.fields["format"];
  1214. if (fmt > FORMAT_VERSION) {
  1215. error_text = "Saved with newer format version";
  1216. _printerr();
  1217. return "";
  1218. }
  1219. }
  1220. if (tag.name == "gd_scene") {
  1221. return "PackedScene";
  1222. }
  1223. if (tag.name != "gd_resource") {
  1224. return "";
  1225. }
  1226. if (!tag.fields.has("type")) {
  1227. error_text = "Missing 'type' field in 'gd_resource' tag";
  1228. _printerr();
  1229. return "";
  1230. }
  1231. return tag.fields["type"];
  1232. }
  1233. ResourceUID::ID ResourceLoaderText::get_uid(Ref<FileAccess> p_f) {
  1234. error = OK;
  1235. lines = 1;
  1236. f = p_f;
  1237. stream.f = f;
  1238. ignore_resource_parsing = true;
  1239. VariantParser::Tag tag;
  1240. Error err = VariantParser::parse_tag(&stream, lines, error_text, tag);
  1241. if (err) {
  1242. _printerr();
  1243. return ResourceUID::INVALID_ID;
  1244. }
  1245. if (tag.fields.has("uid")) { //field is optional
  1246. String uidt = tag.fields["uid"];
  1247. return ResourceUID::get_singleton()->text_to_id(uidt);
  1248. }
  1249. return ResourceUID::INVALID_ID;
  1250. }
  1251. /////////////////////
  1252. Ref<Resource> ResourceFormatLoaderText::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
  1253. if (r_error) {
  1254. *r_error = ERR_CANT_OPEN;
  1255. }
  1256. Error err;
  1257. Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err);
  1258. ERR_FAIL_COND_V_MSG(err != OK, Ref<Resource>(), "Cannot open file '" + p_path + "'.");
  1259. ResourceLoaderText loader;
  1260. String path = !p_original_path.is_empty() ? p_original_path : p_path;
  1261. loader.cache_mode = p_cache_mode;
  1262. loader.use_sub_threads = p_use_sub_threads;
  1263. loader.local_path = ProjectSettings::get_singleton()->localize_path(path);
  1264. loader.progress = r_progress;
  1265. loader.res_path = loader.local_path;
  1266. loader.open(f);
  1267. err = loader.load();
  1268. if (r_error) {
  1269. *r_error = err;
  1270. }
  1271. if (err == OK) {
  1272. return loader.get_resource();
  1273. } else {
  1274. return Ref<Resource>();
  1275. }
  1276. }
  1277. void ResourceFormatLoaderText::get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const {
  1278. if (p_type.is_empty()) {
  1279. get_recognized_extensions(p_extensions);
  1280. return;
  1281. }
  1282. if (ClassDB::is_parent_class("PackedScene", p_type)) {
  1283. p_extensions->push_back("tscn");
  1284. }
  1285. // Don't allow .tres for PackedScenes.
  1286. if (p_type != "PackedScene") {
  1287. p_extensions->push_back("tres");
  1288. }
  1289. }
  1290. void ResourceFormatLoaderText::get_recognized_extensions(List<String> *p_extensions) const {
  1291. p_extensions->push_back("tscn");
  1292. p_extensions->push_back("tres");
  1293. }
  1294. bool ResourceFormatLoaderText::handles_type(const String &p_type) const {
  1295. return true;
  1296. }
  1297. void ResourceFormatLoaderText::get_classes_used(const String &p_path, HashSet<StringName> *r_classes) {
  1298. String ext = p_path.get_extension().to_lower();
  1299. if (ext == "tscn") {
  1300. r_classes->insert("PackedScene");
  1301. }
  1302. // ...for anything else must test...
  1303. Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
  1304. if (f.is_null()) {
  1305. return; // Could not read.
  1306. }
  1307. ResourceLoaderText loader;
  1308. loader.local_path = ProjectSettings::get_singleton()->localize_path(p_path);
  1309. loader.res_path = loader.local_path;
  1310. loader.open(f);
  1311. loader.get_classes_used(r_classes);
  1312. }
  1313. String ResourceFormatLoaderText::get_resource_type(const String &p_path) const {
  1314. String ext = p_path.get_extension().to_lower();
  1315. if (ext == "tscn") {
  1316. return "PackedScene";
  1317. } else if (ext != "tres") {
  1318. return String();
  1319. }
  1320. // ...for anything else must test...
  1321. Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
  1322. if (f.is_null()) {
  1323. return ""; //could not read
  1324. }
  1325. ResourceLoaderText loader;
  1326. loader.local_path = ProjectSettings::get_singleton()->localize_path(p_path);
  1327. loader.res_path = loader.local_path;
  1328. String r = loader.recognize(f);
  1329. return ClassDB::get_compatibility_remapped_class(r);
  1330. }
  1331. ResourceUID::ID ResourceFormatLoaderText::get_resource_uid(const String &p_path) const {
  1332. String ext = p_path.get_extension().to_lower();
  1333. if (ext != "tscn" && ext != "tres") {
  1334. return ResourceUID::INVALID_ID;
  1335. }
  1336. Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
  1337. if (f.is_null()) {
  1338. return ResourceUID::INVALID_ID; //could not read
  1339. }
  1340. ResourceLoaderText loader;
  1341. loader.local_path = ProjectSettings::get_singleton()->localize_path(p_path);
  1342. loader.res_path = loader.local_path;
  1343. return loader.get_uid(f);
  1344. }
  1345. void ResourceFormatLoaderText::get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types) {
  1346. Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
  1347. if (f.is_null()) {
  1348. ERR_FAIL();
  1349. }
  1350. ResourceLoaderText loader;
  1351. loader.local_path = ProjectSettings::get_singleton()->localize_path(p_path);
  1352. loader.res_path = loader.local_path;
  1353. loader.get_dependencies(f, p_dependencies, p_add_types);
  1354. }
  1355. Error ResourceFormatLoaderText::rename_dependencies(const String &p_path, const HashMap<String, String> &p_map) {
  1356. Error err = OK;
  1357. {
  1358. Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
  1359. if (f.is_null()) {
  1360. ERR_FAIL_V(ERR_CANT_OPEN);
  1361. }
  1362. ResourceLoaderText loader;
  1363. loader.local_path = ProjectSettings::get_singleton()->localize_path(p_path);
  1364. loader.res_path = loader.local_path;
  1365. err = loader.rename_dependencies(f, p_path, p_map);
  1366. }
  1367. if (err == OK) {
  1368. Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
  1369. da->remove(p_path);
  1370. da->rename(p_path + ".depren", p_path);
  1371. }
  1372. return err;
  1373. }
  1374. ResourceFormatLoaderText *ResourceFormatLoaderText::singleton = nullptr;
  1375. Error ResourceFormatLoaderText::convert_file_to_binary(const String &p_src_path, const String &p_dst_path) {
  1376. Error err;
  1377. Ref<FileAccess> f = FileAccess::open(p_src_path, FileAccess::READ, &err);
  1378. ERR_FAIL_COND_V_MSG(err != OK, ERR_CANT_OPEN, "Cannot open file '" + p_src_path + "'.");
  1379. ResourceLoaderText loader;
  1380. const String &path = p_src_path;
  1381. loader.local_path = ProjectSettings::get_singleton()->localize_path(path);
  1382. loader.res_path = loader.local_path;
  1383. loader.open(f);
  1384. return loader.save_as_binary(p_dst_path);
  1385. }
  1386. /*****************************************************************************************************/
  1387. /*****************************************************************************************************/
  1388. /*****************************************************************************************************/
  1389. /*****************************************************************************************************/
  1390. /*****************************************************************************************************/
  1391. /*****************************************************************************************************/
  1392. /*****************************************************************************************************/
  1393. /*****************************************************************************************************/
  1394. /*****************************************************************************************************/
  1395. /*****************************************************************************************************/
  1396. String ResourceFormatSaverTextInstance::_write_resources(void *ud, const Ref<Resource> &p_resource) {
  1397. ResourceFormatSaverTextInstance *rsi = static_cast<ResourceFormatSaverTextInstance *>(ud);
  1398. return rsi->_write_resource(p_resource);
  1399. }
  1400. String ResourceFormatSaverTextInstance::_write_resource(const Ref<Resource> &res) {
  1401. if (external_resources.has(res)) {
  1402. return "ExtResource(\"" + external_resources[res] + "\")";
  1403. } else {
  1404. if (internal_resources.has(res)) {
  1405. return "SubResource(\"" + internal_resources[res] + "\")";
  1406. } else if (!res->is_built_in()) {
  1407. if (res->get_path() == local_path) { //circular reference attempt
  1408. return "null";
  1409. }
  1410. //external resource
  1411. String path = relative_paths ? local_path.path_to_file(res->get_path()) : res->get_path();
  1412. return "Resource(\"" + path + "\")";
  1413. } else {
  1414. ERR_FAIL_V_MSG("null", "Resource was not pre cached for the resource section, bug?");
  1415. //internal resource
  1416. }
  1417. }
  1418. }
  1419. void ResourceFormatSaverTextInstance::_find_resources(const Variant &p_variant, bool p_main) {
  1420. switch (p_variant.get_type()) {
  1421. case Variant::OBJECT: {
  1422. Ref<Resource> res = p_variant;
  1423. if (res.is_null() || external_resources.has(res)) {
  1424. return;
  1425. }
  1426. if (!p_main && (!bundle_resources) && !res->is_built_in()) {
  1427. if (res->get_path() == local_path) {
  1428. ERR_PRINT("Circular reference to resource being saved found: '" + local_path + "' will be null next time it's loaded.");
  1429. return;
  1430. }
  1431. // Use a numeric ID as a base, because they are sorted in natural order before saving.
  1432. // This increases the chances of thread loading to fetch them first.
  1433. String id = itos(external_resources.size() + 1) + "_" + Resource::generate_scene_unique_id();
  1434. external_resources[res] = id;
  1435. return;
  1436. }
  1437. if (resource_set.has(res)) {
  1438. return;
  1439. }
  1440. List<PropertyInfo> property_list;
  1441. res->get_property_list(&property_list);
  1442. property_list.sort();
  1443. List<PropertyInfo>::Element *I = property_list.front();
  1444. while (I) {
  1445. PropertyInfo pi = I->get();
  1446. if (pi.usage & PROPERTY_USAGE_STORAGE) {
  1447. Variant v = res->get(I->get().name);
  1448. if (pi.usage & PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT) {
  1449. Ref<Resource> sres = v;
  1450. if (sres.is_valid()) {
  1451. NonPersistentKey npk;
  1452. npk.base = res;
  1453. npk.property = pi.name;
  1454. non_persistent_map[npk] = sres;
  1455. resource_set.insert(sres);
  1456. saved_resources.push_back(sres);
  1457. }
  1458. } else {
  1459. _find_resources(v);
  1460. }
  1461. }
  1462. I = I->next();
  1463. }
  1464. resource_set.insert(res); //saved after, so the children it needs are available when loaded
  1465. saved_resources.push_back(res);
  1466. } break;
  1467. case Variant::ARRAY: {
  1468. Array varray = p_variant;
  1469. int len = varray.size();
  1470. for (int i = 0; i < len; i++) {
  1471. const Variant &v = varray.get(i);
  1472. _find_resources(v);
  1473. }
  1474. } break;
  1475. case Variant::DICTIONARY: {
  1476. Dictionary d = p_variant;
  1477. List<Variant> keys;
  1478. d.get_key_list(&keys);
  1479. for (const Variant &E : keys) {
  1480. Variant v = d[E];
  1481. _find_resources(v);
  1482. }
  1483. } break;
  1484. default: {
  1485. }
  1486. }
  1487. }
  1488. static String _resource_get_class(Ref<Resource> p_resource) {
  1489. Ref<MissingResource> missing_resource = p_resource;
  1490. if (missing_resource.is_valid()) {
  1491. return missing_resource->get_original_class();
  1492. } else {
  1493. return p_resource->get_class();
  1494. }
  1495. }
  1496. Error ResourceFormatSaverTextInstance::save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags) {
  1497. if (p_path.ends_with(".tscn")) {
  1498. packed_scene = p_resource;
  1499. }
  1500. Error err;
  1501. Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE, &err);
  1502. ERR_FAIL_COND_V_MSG(err, ERR_CANT_OPEN, "Cannot save file '" + p_path + "'.");
  1503. Ref<FileAccess> _fref(f);
  1504. local_path = ProjectSettings::get_singleton()->localize_path(p_path);
  1505. relative_paths = p_flags & ResourceSaver::FLAG_RELATIVE_PATHS;
  1506. skip_editor = p_flags & ResourceSaver::FLAG_OMIT_EDITOR_PROPERTIES;
  1507. bundle_resources = p_flags & ResourceSaver::FLAG_BUNDLE_RESOURCES;
  1508. takeover_paths = p_flags & ResourceSaver::FLAG_REPLACE_SUBRESOURCE_PATHS;
  1509. if (!p_path.begins_with("res://")) {
  1510. takeover_paths = false;
  1511. }
  1512. // Save resources.
  1513. _find_resources(p_resource, true);
  1514. if (packed_scene.is_valid()) {
  1515. // Add instances to external resources if saving a packed scene.
  1516. for (int i = 0; i < packed_scene->get_state()->get_node_count(); i++) {
  1517. if (packed_scene->get_state()->is_node_instance_placeholder(i)) {
  1518. continue;
  1519. }
  1520. Ref<PackedScene> instance = packed_scene->get_state()->get_node_instance(i);
  1521. if (instance.is_valid() && !external_resources.has(instance)) {
  1522. int index = external_resources.size() + 1;
  1523. external_resources[instance] = itos(index) + "_" + Resource::generate_scene_unique_id(); // Keep the order for improved thread loading performance.
  1524. }
  1525. }
  1526. }
  1527. {
  1528. String title = packed_scene.is_valid() ? "[gd_scene " : "[gd_resource ";
  1529. if (packed_scene.is_null()) {
  1530. title += "type=\"" + _resource_get_class(p_resource) + "\" ";
  1531. }
  1532. int load_steps = saved_resources.size() + external_resources.size();
  1533. if (load_steps > 1) {
  1534. title += "load_steps=" + itos(load_steps) + " ";
  1535. }
  1536. title += "format=" + itos(FORMAT_VERSION) + "";
  1537. ResourceUID::ID uid = ResourceSaver::get_resource_id_for_path(local_path, true);
  1538. if (uid != ResourceUID::INVALID_ID) {
  1539. title += " uid=\"" + ResourceUID::get_singleton()->id_to_text(uid) + "\"";
  1540. }
  1541. f->store_string(title);
  1542. f->store_line("]\n"); // One empty line.
  1543. }
  1544. #ifdef TOOLS_ENABLED
  1545. // Keep order from cached ids.
  1546. HashSet<String> cached_ids_found;
  1547. for (KeyValue<Ref<Resource>, String> &E : external_resources) {
  1548. String cached_id = E.key->get_id_for_path(local_path);
  1549. if (cached_id.is_empty() || cached_ids_found.has(cached_id)) {
  1550. int sep_pos = E.value.find("_");
  1551. if (sep_pos != -1) {
  1552. E.value = E.value.substr(0, sep_pos + 1); // Keep the order found, for improved thread loading performance.
  1553. } else {
  1554. E.value = "";
  1555. }
  1556. } else {
  1557. E.value = cached_id;
  1558. cached_ids_found.insert(cached_id);
  1559. }
  1560. }
  1561. // Create IDs for non cached resources.
  1562. for (KeyValue<Ref<Resource>, String> &E : external_resources) {
  1563. if (cached_ids_found.has(E.value)) { // Already cached, go on.
  1564. continue;
  1565. }
  1566. String attempt;
  1567. while (true) {
  1568. attempt = E.value + Resource::generate_scene_unique_id();
  1569. if (!cached_ids_found.has(attempt)) {
  1570. break;
  1571. }
  1572. }
  1573. cached_ids_found.insert(attempt);
  1574. E.value = attempt;
  1575. // Update also in resource.
  1576. Ref<Resource> res = E.key;
  1577. res->set_id_for_path(local_path, attempt);
  1578. }
  1579. #else
  1580. // Make sure to start from one, as it makes format more readable.
  1581. int counter = 1;
  1582. for (KeyValue<Ref<Resource>, String> &E : external_resources) {
  1583. E.value = itos(counter++);
  1584. }
  1585. #endif
  1586. Vector<ResourceSort> sorted_er;
  1587. for (const KeyValue<Ref<Resource>, String> &E : external_resources) {
  1588. ResourceSort rs;
  1589. rs.resource = E.key;
  1590. rs.id = E.value;
  1591. sorted_er.push_back(rs);
  1592. }
  1593. sorted_er.sort();
  1594. for (int i = 0; i < sorted_er.size(); i++) {
  1595. String p = sorted_er[i].resource->get_path();
  1596. String s = "[ext_resource type=\"" + sorted_er[i].resource->get_save_class() + "\"";
  1597. ResourceUID::ID uid = ResourceSaver::get_resource_id_for_path(p, false);
  1598. if (uid != ResourceUID::INVALID_ID) {
  1599. s += " uid=\"" + ResourceUID::get_singleton()->id_to_text(uid) + "\"";
  1600. }
  1601. s += " path=\"" + p + "\" id=\"" + sorted_er[i].id + "\"]\n";
  1602. f->store_string(s); // Bundled.
  1603. }
  1604. if (external_resources.size()) {
  1605. f->store_line(String()); // Separate.
  1606. }
  1607. HashSet<String> used_unique_ids;
  1608. for (List<Ref<Resource>>::Element *E = saved_resources.front(); E; E = E->next()) {
  1609. Ref<Resource> res = E->get();
  1610. if (E->next() && res->is_built_in()) {
  1611. if (!res->get_scene_unique_id().is_empty()) {
  1612. if (used_unique_ids.has(res->get_scene_unique_id())) {
  1613. res->set_scene_unique_id(""); // Repeated.
  1614. } else {
  1615. used_unique_ids.insert(res->get_scene_unique_id());
  1616. }
  1617. }
  1618. }
  1619. }
  1620. for (List<Ref<Resource>>::Element *E = saved_resources.front(); E; E = E->next()) {
  1621. Ref<Resource> res = E->get();
  1622. ERR_CONTINUE(!resource_set.has(res));
  1623. bool main = (E->next() == nullptr);
  1624. if (main && packed_scene.is_valid()) {
  1625. break; // Save as a scene.
  1626. }
  1627. if (main) {
  1628. f->store_line("[resource]");
  1629. } else {
  1630. String line = "[sub_resource ";
  1631. if (res->get_scene_unique_id().is_empty()) {
  1632. String new_id;
  1633. while (true) {
  1634. new_id = _resource_get_class(res) + "_" + Resource::generate_scene_unique_id();
  1635. if (!used_unique_ids.has(new_id)) {
  1636. break;
  1637. }
  1638. }
  1639. res->set_scene_unique_id(new_id);
  1640. used_unique_ids.insert(new_id);
  1641. }
  1642. String id = res->get_scene_unique_id();
  1643. line += "type=\"" + _resource_get_class(res) + "\" id=\"" + id;
  1644. f->store_line(line + "\"]");
  1645. if (takeover_paths) {
  1646. res->set_path(p_path + "::" + id, true);
  1647. }
  1648. internal_resources[res] = id;
  1649. #ifdef TOOLS_ENABLED
  1650. res->set_edited(false);
  1651. #endif
  1652. }
  1653. Dictionary missing_resource_properties = p_resource->get_meta(META_MISSING_RESOURCES, Dictionary());
  1654. List<PropertyInfo> property_list;
  1655. res->get_property_list(&property_list);
  1656. for (List<PropertyInfo>::Element *PE = property_list.front(); PE; PE = PE->next()) {
  1657. if (skip_editor && PE->get().name.begins_with("__editor")) {
  1658. continue;
  1659. }
  1660. if (PE->get().name == META_PROPERTY_MISSING_RESOURCES) {
  1661. continue;
  1662. }
  1663. if (PE->get().usage & PROPERTY_USAGE_STORAGE) {
  1664. String name = PE->get().name;
  1665. Variant value;
  1666. if (PE->get().usage & PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT) {
  1667. NonPersistentKey npk;
  1668. npk.base = res;
  1669. npk.property = name;
  1670. if (non_persistent_map.has(npk)) {
  1671. value = non_persistent_map[npk];
  1672. }
  1673. } else {
  1674. value = res->get(name);
  1675. }
  1676. if (PE->get().type == Variant::OBJECT && missing_resource_properties.has(PE->get().name)) {
  1677. // Was this missing resource overridden? If so do not save the old value.
  1678. Ref<Resource> ures = value;
  1679. if (ures.is_null()) {
  1680. value = missing_resource_properties[PE->get().name];
  1681. }
  1682. }
  1683. Variant default_value = ClassDB::class_get_default_property_value(res->get_class(), name);
  1684. if (default_value.get_type() != Variant::NIL && bool(Variant::evaluate(Variant::OP_EQUAL, value, default_value))) {
  1685. continue;
  1686. }
  1687. if (PE->get().type == Variant::OBJECT && value.is_zero() && !(PE->get().usage & PROPERTY_USAGE_STORE_IF_NULL)) {
  1688. continue;
  1689. }
  1690. String vars;
  1691. VariantWriter::write_to_string(value, vars, _write_resources, this);
  1692. f->store_string(name.property_name_encode() + " = " + vars + "\n");
  1693. }
  1694. }
  1695. if (E->next()) {
  1696. f->store_line(String());
  1697. }
  1698. }
  1699. if (packed_scene.is_valid()) {
  1700. // If this is a scene, save nodes and connections!
  1701. Ref<SceneState> state = packed_scene->get_state();
  1702. for (int i = 0; i < state->get_node_count(); i++) {
  1703. StringName type = state->get_node_type(i);
  1704. StringName name = state->get_node_name(i);
  1705. int index = state->get_node_index(i);
  1706. NodePath path = state->get_node_path(i, true);
  1707. NodePath owner = state->get_node_owner_path(i);
  1708. Ref<PackedScene> instance = state->get_node_instance(i);
  1709. String instance_placeholder = state->get_node_instance_placeholder(i);
  1710. Vector<StringName> groups = state->get_node_groups(i);
  1711. Vector<String> deferred_node_paths = state->get_node_deferred_nodepath_properties(i);
  1712. String header = "[node";
  1713. header += " name=\"" + String(name).c_escape() + "\"";
  1714. if (type != StringName()) {
  1715. header += " type=\"" + String(type) + "\"";
  1716. }
  1717. if (path != NodePath()) {
  1718. header += " parent=\"" + String(path.simplified()).c_escape() + "\"";
  1719. }
  1720. if (owner != NodePath() && owner != NodePath(".")) {
  1721. header += " owner=\"" + String(owner.simplified()).c_escape() + "\"";
  1722. }
  1723. if (index >= 0) {
  1724. header += " index=\"" + itos(index) + "\"";
  1725. }
  1726. if (deferred_node_paths.size()) {
  1727. header += " node_paths=" + Variant(deferred_node_paths).get_construct_string();
  1728. }
  1729. if (groups.size()) {
  1730. // Write all groups on the same line as they're part of a section header.
  1731. // This improves readability while not impacting VCS friendliness too much,
  1732. // since it's rare to have more than 5 groups assigned to a single node.
  1733. groups.sort_custom<StringName::AlphCompare>();
  1734. String sgroups = " groups=[";
  1735. for (int j = 0; j < groups.size(); j++) {
  1736. sgroups += "\"" + String(groups[j]).c_escape() + "\"";
  1737. if (j < groups.size() - 1) {
  1738. sgroups += ", ";
  1739. }
  1740. }
  1741. sgroups += "]";
  1742. header += sgroups;
  1743. }
  1744. f->store_string(header);
  1745. if (!instance_placeholder.is_empty()) {
  1746. String vars;
  1747. f->store_string(" instance_placeholder=");
  1748. VariantWriter::write_to_string(instance_placeholder, vars, _write_resources, this);
  1749. f->store_string(vars);
  1750. }
  1751. if (instance.is_valid()) {
  1752. String vars;
  1753. f->store_string(" instance=");
  1754. VariantWriter::write_to_string(instance, vars, _write_resources, this);
  1755. f->store_string(vars);
  1756. }
  1757. f->store_line("]");
  1758. for (int j = 0; j < state->get_node_property_count(i); j++) {
  1759. String vars;
  1760. VariantWriter::write_to_string(state->get_node_property_value(i, j), vars, _write_resources, this);
  1761. f->store_string(String(state->get_node_property_name(i, j)).property_name_encode() + " = " + vars + "\n");
  1762. }
  1763. if (i < state->get_node_count() - 1) {
  1764. f->store_line(String());
  1765. }
  1766. }
  1767. for (int i = 0; i < state->get_connection_count(); i++) {
  1768. if (i == 0) {
  1769. f->store_line("");
  1770. }
  1771. String connstr = "[connection";
  1772. connstr += " signal=\"" + String(state->get_connection_signal(i)) + "\"";
  1773. connstr += " from=\"" + String(state->get_connection_source(i).simplified()) + "\"";
  1774. connstr += " to=\"" + String(state->get_connection_target(i).simplified()) + "\"";
  1775. connstr += " method=\"" + String(state->get_connection_method(i)) + "\"";
  1776. int flags = state->get_connection_flags(i);
  1777. if (flags != Object::CONNECT_PERSIST) {
  1778. connstr += " flags=" + itos(flags);
  1779. }
  1780. int unbinds = state->get_connection_unbinds(i);
  1781. if (unbinds > 0) {
  1782. connstr += " unbinds=" + itos(unbinds);
  1783. }
  1784. Array binds = state->get_connection_binds(i);
  1785. f->store_string(connstr);
  1786. if (binds.size()) {
  1787. String vars;
  1788. VariantWriter::write_to_string(binds, vars, _write_resources, this);
  1789. f->store_string(" binds= " + vars);
  1790. }
  1791. f->store_line("]");
  1792. }
  1793. Vector<NodePath> editable_instances = state->get_editable_instances();
  1794. for (int i = 0; i < editable_instances.size(); i++) {
  1795. if (i == 0) {
  1796. f->store_line("");
  1797. }
  1798. f->store_line("[editable path=\"" + editable_instances[i].operator String() + "\"]");
  1799. }
  1800. }
  1801. if (f->get_error() != OK && f->get_error() != ERR_FILE_EOF) {
  1802. return ERR_CANT_CREATE;
  1803. }
  1804. return OK;
  1805. }
  1806. Error ResourceFormatSaverText::save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags) {
  1807. if (p_path.ends_with(".tscn") && !Ref<PackedScene>(p_resource).is_valid()) {
  1808. return ERR_FILE_UNRECOGNIZED;
  1809. }
  1810. ResourceFormatSaverTextInstance saver;
  1811. return saver.save(p_path, p_resource, p_flags);
  1812. }
  1813. bool ResourceFormatSaverText::recognize(const Ref<Resource> &p_resource) const {
  1814. return true; // All resources recognized!
  1815. }
  1816. void ResourceFormatSaverText::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const {
  1817. if (Ref<PackedScene>(p_resource).is_valid()) {
  1818. p_extensions->push_back("tscn"); // Text scene.
  1819. } else {
  1820. p_extensions->push_back("tres"); // Text resource.
  1821. }
  1822. }
  1823. ResourceFormatSaverText *ResourceFormatSaverText::singleton = nullptr;
  1824. ResourceFormatSaverText::ResourceFormatSaverText() {
  1825. singleton = this;
  1826. }