global_config.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970
  1. /*************************************************************************/
  2. /* globals.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* http://www.godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2017 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 "global_config.h"
  31. #include "bind/core_bind.h"
  32. #include "io/file_access_network.h"
  33. #include "io/file_access_pack.h"
  34. #include "io/marshalls.h"
  35. #include "os/dir_access.h"
  36. #include "os/file_access.h"
  37. #include "os/keyboard.h"
  38. #include "os/os.h"
  39. #include "variant_parser.h"
  40. #include <zlib.h>
  41. #define FORMAT_VERSION 3
  42. GlobalConfig *GlobalConfig::singleton = NULL;
  43. GlobalConfig *GlobalConfig::get_singleton() {
  44. return singleton;
  45. }
  46. String GlobalConfig::get_resource_path() const {
  47. return resource_path;
  48. };
  49. String GlobalConfig::localize_path(const String &p_path) const {
  50. if (resource_path == "")
  51. return p_path; //not initialied yet
  52. if (p_path.begins_with("res://") || p_path.begins_with("user://") ||
  53. (p_path.is_abs_path() && !p_path.begins_with(resource_path)))
  54. return p_path.simplify_path();
  55. DirAccess *dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
  56. String path = p_path.replace("\\", "/").simplify_path();
  57. if (dir->change_dir(path) == OK) {
  58. String cwd = dir->get_current_dir();
  59. cwd = cwd.replace("\\", "/");
  60. memdelete(dir);
  61. if (!cwd.begins_with(resource_path)) {
  62. return p_path;
  63. };
  64. return cwd.replace_first(resource_path, "res:/");
  65. } else {
  66. memdelete(dir);
  67. int sep = path.find_last("/");
  68. if (sep == -1) {
  69. return "res://" + path;
  70. };
  71. String parent = path.substr(0, sep);
  72. String plocal = localize_path(parent);
  73. if (plocal == "") {
  74. return "";
  75. };
  76. return plocal + path.substr(sep, path.size() - sep);
  77. };
  78. }
  79. void GlobalConfig::set_initial_value(const String &p_name, const Variant &p_value) {
  80. ERR_FAIL_COND(!props.has(p_name));
  81. props[p_name].initial = p_value;
  82. }
  83. String GlobalConfig::globalize_path(const String &p_path) const {
  84. if (p_path.begins_with("res://")) {
  85. if (resource_path != "") {
  86. return p_path.replace("res:/", resource_path);
  87. };
  88. return p_path.replace("res://", "");
  89. };
  90. return p_path;
  91. }
  92. bool GlobalConfig::_set(const StringName &p_name, const Variant &p_value) {
  93. _THREAD_SAFE_METHOD_
  94. if (p_value.get_type() == Variant::NIL)
  95. props.erase(p_name);
  96. else {
  97. if (props.has(p_name)) {
  98. if (!props[p_name].overrided)
  99. props[p_name].variant = p_value;
  100. } else {
  101. props[p_name] = VariantContainer(p_value, last_order++);
  102. }
  103. }
  104. return true;
  105. }
  106. bool GlobalConfig::_get(const StringName &p_name, Variant &r_ret) const {
  107. _THREAD_SAFE_METHOD_
  108. if (!props.has(p_name)) {
  109. print_line("WARNING: not found: " + String(p_name));
  110. return false;
  111. }
  112. r_ret = props[p_name].variant;
  113. return true;
  114. }
  115. struct _VCSort {
  116. String name;
  117. Variant::Type type;
  118. int order;
  119. int flags;
  120. bool operator<(const _VCSort &p_vcs) const { return order == p_vcs.order ? name < p_vcs.name : order < p_vcs.order; }
  121. };
  122. void GlobalConfig::_get_property_list(List<PropertyInfo> *p_list) const {
  123. _THREAD_SAFE_METHOD_
  124. Set<_VCSort> vclist;
  125. for (Map<StringName, VariantContainer>::Element *E = props.front(); E; E = E->next()) {
  126. const VariantContainer *v = &E->get();
  127. if (v->hide_from_editor)
  128. continue;
  129. _VCSort vc;
  130. vc.name = E->key();
  131. vc.order = v->order;
  132. vc.type = v->variant.get_type();
  133. if (vc.name.begins_with("input/") || vc.name.begins_with("import/") || vc.name.begins_with("export/") || vc.name.begins_with("/remap") || vc.name.begins_with("/locale") || vc.name.begins_with("/autoload"))
  134. vc.flags = PROPERTY_USAGE_STORAGE;
  135. else
  136. vc.flags = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE;
  137. vclist.insert(vc);
  138. }
  139. for (Set<_VCSort>::Element *E = vclist.front(); E; E = E->next()) {
  140. if (custom_prop_info.has(E->get().name)) {
  141. PropertyInfo pi = custom_prop_info[E->get().name];
  142. pi.name = E->get().name;
  143. pi.usage = E->get().flags;
  144. p_list->push_back(pi);
  145. } else
  146. p_list->push_back(PropertyInfo(E->get().type, E->get().name, PROPERTY_HINT_NONE, "", E->get().flags));
  147. }
  148. }
  149. bool GlobalConfig::_load_resource_pack(const String &p_pack) {
  150. if (PackedData::get_singleton()->is_disabled())
  151. return false;
  152. bool ok = PackedData::get_singleton()->add_pack(p_pack) == OK;
  153. if (!ok)
  154. return false;
  155. //if data.pck is found, all directory access will be from here
  156. DirAccess::make_default<DirAccessPack>(DirAccess::ACCESS_RESOURCES);
  157. using_datapack = true;
  158. return true;
  159. }
  160. Error GlobalConfig::setup(const String &p_path, const String &p_main_pack) {
  161. //If looking for files in network, just use network!
  162. if (FileAccessNetworkClient::get_singleton()) {
  163. if (_load_settings("res://project.godot") == OK || _load_settings_binary("res://godot.cfb") == OK) {
  164. _load_settings("res://override.cfg");
  165. }
  166. return OK;
  167. }
  168. String exec_path = OS::get_singleton()->get_executable_path();
  169. //Attempt with a passed main pack first
  170. if (p_main_pack != "") {
  171. bool ok = _load_resource_pack(p_main_pack);
  172. ERR_FAIL_COND_V(!ok, ERR_CANT_OPEN);
  173. if (_load_settings("res://project.godot") == OK || _load_settings_binary("res://godot.cfb") == OK) {
  174. //load override from location of the main pack
  175. _load_settings(p_main_pack.get_base_dir().plus_file("override.cfg"));
  176. }
  177. return OK;
  178. }
  179. //Attempt with execname.pck
  180. if (exec_path != "") {
  181. if (_load_resource_pack(exec_path.get_basename() + ".pck")) {
  182. if (_load_settings("res://project.godot") == OK || _load_settings_binary("res://godot.cfb") == OK) {
  183. //load override from location of executable
  184. _load_settings(exec_path.get_base_dir().plus_file("override.cfg"));
  185. }
  186. return OK;
  187. }
  188. }
  189. //Try to use the filesystem for files, according to OS. (only Android -when reading from pck- and iOS use this)
  190. if (OS::get_singleton()->get_resource_dir() != "") {
  191. //OS will call Globals->get_resource_path which will be empty if not overridden!
  192. //if the OS would rather use somewhere else, then it will not be empty.
  193. resource_path = OS::get_singleton()->get_resource_dir().replace("\\", "/");
  194. if (resource_path.length() && resource_path[resource_path.length() - 1] == '/')
  195. resource_path = resource_path.substr(0, resource_path.length() - 1); // chop end
  196. // data.pck and data.zip are deprecated and no longer supported, apologies.
  197. // make sure this is loaded from the resource path
  198. if (_load_settings("res://project.godot") == OK || _load_settings_binary("res://godot.cfb") == OK) {
  199. _load_settings("res://override.cfg");
  200. }
  201. return OK;
  202. }
  203. //Nothing was found, try to find a project.godot somewhere!
  204. DirAccess *d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
  205. ERR_FAIL_COND_V(!d, ERR_CANT_CREATE);
  206. d->change_dir(p_path);
  207. String candidate = d->get_current_dir();
  208. String current_dir = d->get_current_dir();
  209. bool found = false;
  210. while (true) {
  211. //try to load settings in ascending through dirs shape!
  212. if (_load_settings(current_dir + "/project.godot") == OK || _load_settings_binary(current_dir + "/godot.cfb") == OK) {
  213. _load_settings(current_dir + "/override.cfg");
  214. candidate = current_dir;
  215. found = true;
  216. break;
  217. }
  218. d->change_dir("..");
  219. if (d->get_current_dir() == current_dir)
  220. break; //not doing anything useful
  221. current_dir = d->get_current_dir();
  222. }
  223. resource_path = candidate;
  224. resource_path = resource_path.replace("\\", "/"); // windows path to unix path just in case
  225. memdelete(d);
  226. if (!found)
  227. return ERR_FILE_NOT_FOUND;
  228. if (resource_path.length() && resource_path[resource_path.length() - 1] == '/')
  229. resource_path = resource_path.substr(0, resource_path.length() - 1); // chop end
  230. return OK;
  231. }
  232. bool GlobalConfig::has(String p_var) const {
  233. _THREAD_SAFE_METHOD_
  234. return props.has(p_var);
  235. }
  236. void GlobalConfig::set_registering_order(bool p_enable) {
  237. registering_order = p_enable;
  238. }
  239. Error GlobalConfig::_load_settings_binary(const String p_path) {
  240. Error err;
  241. FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err);
  242. if (err != OK) {
  243. return err;
  244. }
  245. uint8_t hdr[4];
  246. f->get_buffer(hdr, 4);
  247. if (hdr[0] != 'E' || hdr[1] != 'C' || hdr[2] != 'F' || hdr[3] != 'G') {
  248. memdelete(f);
  249. ERR_EXPLAIN("Corrupted header in binary godot.cfb (not ECFG)");
  250. ERR_FAIL_V(ERR_FILE_CORRUPT;)
  251. }
  252. uint32_t count = f->get_32();
  253. for (uint32_t i = 0; i < count; i++) {
  254. uint32_t slen = f->get_32();
  255. CharString cs;
  256. cs.resize(slen + 1);
  257. cs[slen] = 0;
  258. f->get_buffer((uint8_t *)cs.ptr(), slen);
  259. String key;
  260. key.parse_utf8(cs.ptr());
  261. uint32_t vlen = f->get_32();
  262. Vector<uint8_t> d;
  263. d.resize(vlen);
  264. f->get_buffer(d.ptr(), vlen);
  265. Variant value;
  266. Error err = decode_variant(value, d.ptr(), d.size());
  267. ERR_EXPLAIN("Error decoding property: " + key);
  268. ERR_CONTINUE(err != OK);
  269. set(key, value);
  270. }
  271. return OK;
  272. }
  273. Error GlobalConfig::_load_settings(const String p_path) {
  274. Error err;
  275. FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err);
  276. if (!f)
  277. return ERR_CANT_OPEN;
  278. VariantParser::StreamFile stream;
  279. stream.f = f;
  280. String assign;
  281. Variant value;
  282. VariantParser::Tag next_tag;
  283. int lines = 0;
  284. String error_text;
  285. String section;
  286. while (true) {
  287. assign = Variant();
  288. next_tag.fields.clear();
  289. next_tag.name = String();
  290. err = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, NULL, true);
  291. if (err == ERR_FILE_EOF) {
  292. memdelete(f);
  293. return OK;
  294. } else if (err != OK) {
  295. ERR_PRINTS("GlobalConfig::load - " + p_path + ":" + itos(lines) + " error: " + error_text);
  296. memdelete(f);
  297. return err;
  298. }
  299. if (assign != String()) {
  300. if (section == String() && assign == "config_version") {
  301. int config_version = value;
  302. if (config_version > FORMAT_VERSION) {
  303. memdelete(f);
  304. ERR_FAIL_COND_V(config_version > FORMAT_VERSION, ERR_FILE_CANT_OPEN);
  305. }
  306. }
  307. set(section + "/" + assign, value);
  308. } else if (next_tag.name != String()) {
  309. section = next_tag.name;
  310. }
  311. }
  312. memdelete(f);
  313. return OK;
  314. }
  315. int GlobalConfig::get_order(const String &p_name) const {
  316. ERR_FAIL_COND_V(!props.has(p_name), -1);
  317. return props[p_name].order;
  318. }
  319. void GlobalConfig::set_order(const String &p_name, int p_order) {
  320. ERR_FAIL_COND(!props.has(p_name));
  321. props[p_name].order = p_order;
  322. }
  323. void GlobalConfig::set_builtin_order(const String &p_name) {
  324. ERR_FAIL_COND(!props.has(p_name));
  325. if (props[p_name].order >= NO_BUILTIN_ORDER_BASE) {
  326. props[p_name].order = last_builtin_order++;
  327. }
  328. }
  329. void GlobalConfig::clear(const String &p_name) {
  330. ERR_FAIL_COND(!props.has(p_name));
  331. props.erase(p_name);
  332. }
  333. Error GlobalConfig::save() {
  334. return save_custom(get_resource_path() + "/project.godot");
  335. }
  336. Error GlobalConfig::_save_settings_binary(const String &p_file, const Map<String, List<String> > &props, const CustomMap &p_custom) {
  337. Error err;
  338. FileAccess *file = FileAccess::open(p_file, FileAccess::WRITE, &err);
  339. if (err != OK) {
  340. ERR_EXPLAIN("Couldn't save godot.cfb at " + p_file);
  341. ERR_FAIL_COND_V(err, err)
  342. }
  343. uint8_t hdr[4] = { 'E', 'C', 'F', 'G' };
  344. file->store_buffer(hdr, 4);
  345. int count = 0;
  346. for (Map<String, List<String> >::Element *E = props.front(); E; E = E->next()) {
  347. for (List<String>::Element *F = E->get().front(); F; F = F->next()) {
  348. count++;
  349. }
  350. }
  351. file->store_32(count); //store how many properties are saved
  352. for (Map<String, List<String> >::Element *E = props.front(); E; E = E->next()) {
  353. for (List<String>::Element *F = E->get().front(); F; F = F->next()) {
  354. String key = F->get();
  355. if (E->key() != "")
  356. key = E->key() + "/" + key;
  357. Variant value;
  358. if (p_custom.has(key))
  359. value = p_custom[key];
  360. else
  361. value = get(key);
  362. file->store_32(key.length());
  363. file->store_string(key);
  364. int len;
  365. Error err = encode_variant(value, NULL, len);
  366. if (err != OK)
  367. memdelete(file);
  368. ERR_FAIL_COND_V(err != OK, ERR_INVALID_DATA);
  369. Vector<uint8_t> buff;
  370. buff.resize(len);
  371. err = encode_variant(value, &buff[0], len);
  372. if (err != OK)
  373. memdelete(file);
  374. ERR_FAIL_COND_V(err != OK, ERR_INVALID_DATA);
  375. file->store_32(len);
  376. file->store_buffer(buff.ptr(), buff.size());
  377. }
  378. }
  379. file->close();
  380. memdelete(file);
  381. return OK;
  382. }
  383. Error GlobalConfig::_save_settings_text(const String &p_file, const Map<String, List<String> > &props, const CustomMap &p_custom) {
  384. Error err;
  385. FileAccess *file = FileAccess::open(p_file, FileAccess::WRITE, &err);
  386. if (err) {
  387. ERR_EXPLAIN("Couldn't save project.godot - " + p_file);
  388. ERR_FAIL_COND_V(err, err)
  389. }
  390. file->store_string("config_version=" + itos(FORMAT_VERSION) + "\n");
  391. for (Map<String, List<String> >::Element *E = props.front(); E; E = E->next()) {
  392. if (E != props.front())
  393. file->store_string("\n");
  394. if (E->key() != "")
  395. file->store_string("[" + E->key() + "]\n\n");
  396. for (List<String>::Element *F = E->get().front(); F; F = F->next()) {
  397. String key = F->get();
  398. if (E->key() != "")
  399. key = E->key() + "/" + key;
  400. Variant value;
  401. if (p_custom.has(key))
  402. value = p_custom[key];
  403. else
  404. value = get(key);
  405. String vstr;
  406. VariantWriter::write_to_string(value, vstr);
  407. file->store_string(F->get() + "=" + vstr + "\n");
  408. }
  409. }
  410. file->close();
  411. memdelete(file);
  412. return OK;
  413. }
  414. Error GlobalConfig::_save_custom_bnd(const String &p_file) { // add other params as dictionary and array?
  415. return save_custom(p_file);
  416. };
  417. Error GlobalConfig::save_custom(const String &p_path, const CustomMap &p_custom, const Set<String> &p_ignore_masks) {
  418. ERR_FAIL_COND_V(p_path == "", ERR_INVALID_PARAMETER);
  419. Set<_VCSort> vclist;
  420. for (Map<StringName, VariantContainer>::Element *G = props.front(); G; G = G->next()) {
  421. const VariantContainer *v = &G->get();
  422. if (v->hide_from_editor)
  423. continue;
  424. if (p_custom.has(G->key()))
  425. continue;
  426. bool discard = false;
  427. for (const Set<String>::Element *E = p_ignore_masks.front(); E; E = E->next()) {
  428. if (String(G->key()).match(E->get())) {
  429. discard = true;
  430. break;
  431. }
  432. }
  433. if (discard)
  434. continue;
  435. _VCSort vc;
  436. vc.name = G->key(); //*k;
  437. vc.order = v->order;
  438. vc.type = v->variant.get_type();
  439. vc.flags = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE;
  440. if (v->variant == v->initial)
  441. continue;
  442. vclist.insert(vc);
  443. }
  444. for (const Map<String, Variant>::Element *E = p_custom.front(); E; E = E->next()) {
  445. _VCSort vc;
  446. vc.name = E->key();
  447. vc.order = 0xFFFFFFF;
  448. vc.type = E->get().get_type();
  449. vc.flags = PROPERTY_USAGE_STORAGE;
  450. vclist.insert(vc);
  451. }
  452. Map<String, List<String> > props;
  453. for (Set<_VCSort>::Element *E = vclist.front(); E; E = E->next()) {
  454. String category = E->get().name;
  455. String name = E->get().name;
  456. int div = category.find("/");
  457. if (div < 0)
  458. category = "";
  459. else {
  460. category = category.substr(0, div);
  461. name = name.substr(div + 1, name.size());
  462. }
  463. props[category].push_back(name);
  464. }
  465. if (p_path.ends_with(".godot"))
  466. return _save_settings_text(p_path, props, p_custom);
  467. else if (p_path.ends_with(".cfb"))
  468. return _save_settings_binary(p_path, props, p_custom);
  469. else {
  470. ERR_EXPLAIN("Unknown config file format: " + p_path);
  471. ERR_FAIL_V(ERR_FILE_UNRECOGNIZED);
  472. }
  473. return OK;
  474. #if 0
  475. Error err = file->open(dst_file,FileAccess::WRITE);
  476. if (err) {
  477. memdelete(file);
  478. ERR_EXPLAIN("Couldn't save project.godot");
  479. ERR_FAIL_COND_V(err,err)
  480. }
  481. for(Map<String,List<String> >::Element *E=props.front();E;E=E->next()) {
  482. if (E!=props.front())
  483. file->store_string("\n");
  484. if (E->key()!="")
  485. file->store_string("["+E->key()+"]\n\n");
  486. for(List<String>::Element *F=E->get().front();F;F=F->next()) {
  487. String key = F->get();
  488. if (E->key()!="")
  489. key=E->key()+"/"+key;
  490. Variant value;
  491. if (p_custom.has(key))
  492. value=p_custom[key];
  493. else
  494. value = get(key);
  495. file->store_string(F->get()+"="+_encode_variant(value)+"\n");
  496. }
  497. }
  498. file->close();
  499. memdelete(file);
  500. return OK;
  501. #endif
  502. }
  503. Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default) {
  504. Variant ret;
  505. if (GlobalConfig::get_singleton()->has(p_var)) {
  506. ret = GlobalConfig::get_singleton()->get(p_var);
  507. } else {
  508. GlobalConfig::get_singleton()->set(p_var, p_default);
  509. ret = p_default;
  510. }
  511. GlobalConfig::get_singleton()->set_initial_value(p_var, p_default);
  512. GlobalConfig::get_singleton()->set_builtin_order(p_var);
  513. return ret;
  514. }
  515. void GlobalConfig::add_singleton(const Singleton &p_singleton) {
  516. singletons.push_back(p_singleton);
  517. singleton_ptrs[p_singleton.name] = p_singleton.ptr;
  518. }
  519. Object *GlobalConfig::get_singleton_object(const String &p_name) const {
  520. const Map<StringName, Object *>::Element *E = singleton_ptrs.find(p_name);
  521. if (!E)
  522. return NULL;
  523. else
  524. return E->get();
  525. };
  526. bool GlobalConfig::has_singleton(const String &p_name) const {
  527. return get_singleton_object(p_name) != NULL;
  528. };
  529. void GlobalConfig::get_singletons(List<Singleton> *p_singletons) {
  530. for (List<Singleton>::Element *E = singletons.front(); E; E = E->next())
  531. p_singletons->push_back(E->get());
  532. }
  533. Vector<String> GlobalConfig::get_optimizer_presets() const {
  534. List<PropertyInfo> pi;
  535. GlobalConfig::get_singleton()->get_property_list(&pi);
  536. Vector<String> names;
  537. for (List<PropertyInfo>::Element *E = pi.front(); E; E = E->next()) {
  538. if (!E->get().name.begins_with("optimizer_presets/"))
  539. continue;
  540. names.push_back(E->get().name.get_slicec('/', 1));
  541. }
  542. names.sort();
  543. return names;
  544. }
  545. void GlobalConfig::_add_property_info_bind(const Dictionary &p_info) {
  546. ERR_FAIL_COND(!p_info.has("name"));
  547. ERR_FAIL_COND(!p_info.has("type"));
  548. PropertyInfo pinfo;
  549. pinfo.name = p_info["name"];
  550. ERR_FAIL_COND(!props.has(pinfo.name));
  551. pinfo.type = Variant::Type(p_info["type"].operator int());
  552. ERR_FAIL_INDEX(pinfo.type, Variant::VARIANT_MAX);
  553. if (p_info.has("hint"))
  554. pinfo.hint = PropertyHint(p_info["hint"].operator int());
  555. if (p_info.has("hint_string"))
  556. pinfo.hint_string = p_info["hint_string"];
  557. set_custom_property_info(pinfo.name, pinfo);
  558. }
  559. void GlobalConfig::set_custom_property_info(const String &p_prop, const PropertyInfo &p_info) {
  560. ERR_FAIL_COND(!props.has(p_prop));
  561. custom_prop_info[p_prop] = p_info;
  562. custom_prop_info[p_prop].name = p_prop;
  563. }
  564. void GlobalConfig::set_disable_platform_override(bool p_disable) {
  565. disable_platform_override = p_disable;
  566. }
  567. bool GlobalConfig::is_using_datapack() const {
  568. return using_datapack;
  569. }
  570. bool GlobalConfig::property_can_revert(const String &p_name) {
  571. if (!props.has(p_name))
  572. return false;
  573. return props[p_name].initial != props[p_name].variant;
  574. }
  575. Variant GlobalConfig::property_get_revert(const String &p_name) {
  576. if (!props.has(p_name))
  577. return Variant();
  578. return props[p_name].initial;
  579. }
  580. void GlobalConfig::_bind_methods() {
  581. ClassDB::bind_method(D_METHOD("has", "name"), &GlobalConfig::has);
  582. ClassDB::bind_method(D_METHOD("set_order", "name", "pos"), &GlobalConfig::set_order);
  583. ClassDB::bind_method(D_METHOD("get_order", "name"), &GlobalConfig::get_order);
  584. ClassDB::bind_method(D_METHOD("set_initial_value", "name", "value"), &GlobalConfig::set_initial_value);
  585. ClassDB::bind_method(D_METHOD("add_property_info", "hint"), &GlobalConfig::_add_property_info_bind);
  586. ClassDB::bind_method(D_METHOD("clear", "name"), &GlobalConfig::clear);
  587. ClassDB::bind_method(D_METHOD("localize_path", "path"), &GlobalConfig::localize_path);
  588. ClassDB::bind_method(D_METHOD("globalize_path", "path"), &GlobalConfig::globalize_path);
  589. ClassDB::bind_method(D_METHOD("save"), &GlobalConfig::save);
  590. ClassDB::bind_method(D_METHOD("has_singleton", "name"), &GlobalConfig::has_singleton);
  591. ClassDB::bind_method(D_METHOD("get_singleton", "name"), &GlobalConfig::get_singleton_object);
  592. ClassDB::bind_method(D_METHOD("load_resource_pack", "pack"), &GlobalConfig::_load_resource_pack);
  593. ClassDB::bind_method(D_METHOD("property_can_revert", "name"), &GlobalConfig::property_can_revert);
  594. ClassDB::bind_method(D_METHOD("property_get_revert:Variant", "name"), &GlobalConfig::property_get_revert);
  595. ClassDB::bind_method(D_METHOD("save_custom", "file"), &GlobalConfig::_save_custom_bnd);
  596. }
  597. GlobalConfig::GlobalConfig() {
  598. singleton = this;
  599. last_order = NO_BUILTIN_ORDER_BASE;
  600. last_builtin_order = 0;
  601. disable_platform_override = false;
  602. registering_order = true;
  603. Array va;
  604. Ref<InputEventKey> key;
  605. Ref<InputEventJoypadButton> joyb;
  606. GLOBAL_DEF("application/config/name", "");
  607. GLOBAL_DEF("application/run/main_scene", "");
  608. custom_prop_info["application/run/main_scene"] = PropertyInfo(Variant::STRING, "application/run/main_scene", PROPERTY_HINT_FILE, "tscn,scn,res");
  609. GLOBAL_DEF("application/run/disable_stdout", false);
  610. GLOBAL_DEF("application/run/disable_stderr", false);
  611. GLOBAL_DEF("application/config/use_shared_user_dir", true);
  612. key.instance();
  613. key->set_scancode(KEY_RETURN);
  614. va.push_back(key);
  615. key.instance();
  616. key->set_scancode(KEY_ENTER);
  617. va.push_back(key);
  618. key.instance();
  619. key->set_scancode(KEY_SPACE);
  620. va.push_back(key);
  621. joyb.instance();
  622. joyb->set_button_index(JOY_BUTTON_0);
  623. va.push_back(joyb);
  624. GLOBAL_DEF("input/ui_accept", va);
  625. input_presets.push_back("input/ui_accept");
  626. va = Array();
  627. key.instance();
  628. key->set_scancode(KEY_SPACE);
  629. va.push_back(key);
  630. joyb.instance();
  631. joyb->set_button_index(JOY_BUTTON_3);
  632. va.push_back(joyb);
  633. GLOBAL_DEF("input/ui_select", va);
  634. input_presets.push_back("input/ui_select");
  635. va = Array();
  636. key.instance();
  637. key->set_scancode(KEY_ESCAPE);
  638. va.push_back(key);
  639. joyb.instance();
  640. joyb->set_button_index(JOY_BUTTON_1);
  641. va.push_back(joyb);
  642. GLOBAL_DEF("input/ui_cancel", va);
  643. input_presets.push_back("input/ui_cancel");
  644. va = Array();
  645. key.instance();
  646. key->set_scancode(KEY_TAB);
  647. va.push_back(key);
  648. GLOBAL_DEF("input/ui_focus_next", va);
  649. input_presets.push_back("input/ui_focus_next");
  650. va = Array();
  651. key.instance();
  652. key->set_scancode(KEY_TAB);
  653. key->set_shift(true);
  654. va.push_back(key);
  655. GLOBAL_DEF("input/ui_focus_prev", va);
  656. input_presets.push_back("input/ui_focus_prev");
  657. va = Array();
  658. key.instance();
  659. key->set_scancode(KEY_LEFT);
  660. va.push_back(key);
  661. joyb.instance();
  662. joyb->set_button_index(JOY_DPAD_LEFT);
  663. va.push_back(joyb);
  664. GLOBAL_DEF("input/ui_left", va);
  665. input_presets.push_back("input/ui_left");
  666. va = Array();
  667. key.instance();
  668. key->set_scancode(KEY_RIGHT);
  669. va.push_back(key);
  670. joyb.instance();
  671. joyb->set_button_index(JOY_DPAD_RIGHT);
  672. va.push_back(joyb);
  673. GLOBAL_DEF("input/ui_right", va);
  674. input_presets.push_back("input/ui_right");
  675. va = Array();
  676. key.instance();
  677. key->set_scancode(KEY_UP);
  678. va.push_back(key);
  679. joyb.instance();
  680. joyb->set_button_index(JOY_DPAD_UP);
  681. va.push_back(joyb);
  682. GLOBAL_DEF("input/ui_up", va);
  683. input_presets.push_back("input/ui_up");
  684. va = Array();
  685. key.instance();
  686. key->set_scancode(KEY_DOWN);
  687. va.push_back(key);
  688. joyb.instance();
  689. joyb->set_button_index(JOY_DPAD_DOWN);
  690. va.push_back(joyb);
  691. GLOBAL_DEF("input/ui_down", va);
  692. input_presets.push_back("input/ui_down");
  693. va = Array();
  694. key.instance();
  695. key->set_scancode(KEY_PAGEUP);
  696. va.push_back(key);
  697. GLOBAL_DEF("input/ui_page_up", va);
  698. input_presets.push_back("input/ui_page_up");
  699. va = Array();
  700. key.instance();
  701. key->set_scancode(KEY_PAGEDOWN);
  702. va.push_back(key);
  703. GLOBAL_DEF("input/ui_page_down", va);
  704. input_presets.push_back("input/ui_page_down");
  705. //GLOBAL_DEF("display/window/handheld/orientation", "landscape");
  706. custom_prop_info["display/window/handheld/orientation"] = PropertyInfo(Variant::STRING, "display/window/handheld/orientation", PROPERTY_HINT_ENUM, "landscape,portrait,reverse_landscape,reverse_portrait,sensor_landscape,sensor_portrait,sensor");
  707. custom_prop_info["rendering/threads/thread_model"] = PropertyInfo(Variant::INT, "rendering/threads/thread_model", PROPERTY_HINT_ENUM, "Single-Unsafe,Single-Safe,Multi-Threaded");
  708. custom_prop_info["physics/2d/thread_model"] = PropertyInfo(Variant::INT, "physics/2d/thread_model", PROPERTY_HINT_ENUM, "Single-Unsafe,Single-Safe,Multi-Threaded");
  709. GLOBAL_DEF("debug/settings/profiler/max_functions", 16384);
  710. //assigning here, because using GLOBAL_GET on every block for compressing can be slow
  711. Compression::zstd_level = GLOBAL_DEF("compression/formats/zstd/compression_level", 3);
  712. custom_prop_info["compression/formats/zstd/compression_level"] = PropertyInfo(Variant::INT, "compression/formats/zstd/compression_level", PROPERTY_HINT_RANGE, "1,22,1");
  713. Compression::zlib_level = GLOBAL_DEF("compression/formats/zlib/compression_level", Z_DEFAULT_COMPRESSION);
  714. custom_prop_info["compression/formats/zlib/compression_level"] = PropertyInfo(Variant::INT, "compression/formats/zlib/compression_level", PROPERTY_HINT_RANGE, "-1,9,1");
  715. Compression::gzip_level = GLOBAL_DEF("compression/formats/gzip/compression_level", Z_DEFAULT_COMPRESSION);
  716. custom_prop_info["compression/formats/gzip/compression_level"] = PropertyInfo(Variant::INT, "compression/formats/gzip/compression_level", PROPERTY_HINT_RANGE, "-1,9,1");
  717. using_datapack = false;
  718. }
  719. GlobalConfig::~GlobalConfig() {
  720. singleton = NULL;
  721. }