globals.cpp 25 KB

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