nativescript.cpp 30 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088
  1. /*************************************************************************/
  2. /* nativescript.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 "nativescript.h"
  31. #include "modules/gdnative/godot/gdnative.h"
  32. #include "global_constants.h"
  33. #include "io/file_access_encrypted.h"
  34. #include "os/file_access.h"
  35. #include "os/os.h"
  36. #include "project_settings.h"
  37. #include "scene/main/scene_tree.h"
  38. #include "scene/resources/scene_format_text.h"
  39. #if defined(TOOLS_ENABLED) && defined(DEBUG_METHODS_ENABLED)
  40. #include "api_generator.h"
  41. #endif
  42. #ifdef TOOLS_ENABLED
  43. #include "editor/editor_node.h"
  44. #endif
  45. ////// Script stuff
  46. void NativeScript::_bind_methods() {
  47. ClassDB::bind_method(D_METHOD("set_class_name", "class_name:String"), &NativeScript::set_class_name);
  48. ClassDB::bind_method(D_METHOD("get_class_name:String"), &NativeScript::get_class_name);
  49. ClassDB::bind_method(D_METHOD("set_library", "library:GDNativeLibrary"), &NativeScript::set_library);
  50. ClassDB::bind_method(D_METHOD("get_library:GDNativeLibrary"), &NativeScript::get_library);
  51. ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "class_name"), "set_class_name", "get_class_name");
  52. ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "library", PROPERTY_HINT_RESOURCE_TYPE, "GDNativeLibrary"), "set_library", "get_library");
  53. }
  54. #define NSL NativeScriptLanguage::get_singleton()
  55. #ifdef TOOLS_ENABLED
  56. void NativeScript::_update_placeholder(PlaceHolderScriptInstance *p_placeholder) {
  57. NativeScriptDesc *script_data = get_script_desc();
  58. ERR_FAIL_COND(!script_data);
  59. List<PropertyInfo> info;
  60. Map<StringName, Variant> values;
  61. for (Map<StringName, NativeScriptDesc::Property>::Element *E = script_data->properties.front(); E; E = E->next()) {
  62. PropertyInfo p = E->get().info;
  63. p.name = String(E->key());
  64. info.push_back(p);
  65. values[p.name] = E->get().default_value;
  66. }
  67. p_placeholder->update(info, values);
  68. }
  69. void NativeScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder) {
  70. placeholders.erase(p_placeholder);
  71. }
  72. #endif
  73. void NativeScript::set_class_name(String p_class_name) {
  74. class_name = p_class_name;
  75. }
  76. String NativeScript::get_class_name() const {
  77. return class_name;
  78. }
  79. void NativeScript::set_library(Ref<GDNativeLibrary> p_library) {
  80. if (!library.is_null()) {
  81. WARN_PRINT("library on NativeScript already set. Do nothing.");
  82. return;
  83. }
  84. library = p_library;
  85. // See if this library was "registered" already.
  86. lib_path = library->get_active_library_path();
  87. Map<String, Ref<GDNative> >::Element *E = NSL->library_gdnatives.find(lib_path);
  88. if (!E) {
  89. Ref<GDNative> gdn;
  90. gdn.instance();
  91. gdn->set_library(library);
  92. // TODO(karroffel): check the return value?
  93. gdn->initialize();
  94. NSL->library_gdnatives.insert(lib_path, gdn);
  95. NSL->library_classes.insert(lib_path, Map<StringName, NativeScriptDesc>());
  96. if (!NSL->library_script_users.has(lib_path))
  97. NSL->library_script_users.insert(lib_path, Set<NativeScript *>());
  98. NSL->library_script_users[lib_path].insert(this);
  99. void *args[1] = {
  100. (void *)&lib_path
  101. };
  102. // here the library registers all the classes and stuff.
  103. gdn->call_native_raw(NSL->_init_call_type,
  104. NSL->_init_call_name,
  105. NULL,
  106. 1,
  107. args,
  108. NULL);
  109. } else {
  110. // already initialized. Nice.
  111. }
  112. }
  113. Ref<GDNativeLibrary> NativeScript::get_library() const {
  114. return library;
  115. }
  116. bool NativeScript::can_instance() const {
  117. NativeScriptDesc *script_data = get_script_desc();
  118. #ifdef TOOLS_ENABLED
  119. return script_data || (!is_tool() && !ScriptServer::is_scripting_enabled());
  120. #else
  121. return script_data;
  122. #endif
  123. }
  124. // TODO(karroffel): implement this
  125. Ref<Script> NativeScript::get_base_script() const {
  126. NativeScriptDesc *script_data = get_script_desc();
  127. if (!script_data)
  128. return Ref<Script>();
  129. Ref<NativeScript> ns = Ref<NativeScript>(NSL->create_script());
  130. ns->set_class_name(script_data->base);
  131. ns->set_library(get_library());
  132. return ns;
  133. }
  134. StringName NativeScript::get_instance_base_type() const {
  135. NativeScriptDesc *script_data = get_script_desc();
  136. if (!script_data)
  137. return "";
  138. return script_data->base_native_type;
  139. }
  140. ScriptInstance *NativeScript::instance_create(Object *p_this) {
  141. NativeScriptDesc *script_data = get_script_desc();
  142. if (!script_data) {
  143. return NULL;
  144. }
  145. #ifdef TOOLS_ENABLED
  146. if (!ScriptServer::is_scripting_enabled() && !is_tool()) {
  147. // placeholder for nodes. For tools we want the rool thing.
  148. PlaceHolderScriptInstance *sins = memnew(PlaceHolderScriptInstance(NSL, Ref<Script>(this), p_this));
  149. placeholders.insert(sins);
  150. if (script_data->create_func.create_func) {
  151. script_data->create_func.create_func(
  152. (godot_object *)p_this,
  153. script_data->create_func.method_data);
  154. }
  155. _update_placeholder(sins);
  156. return sins;
  157. }
  158. #endif
  159. NativeScriptInstance *nsi = memnew(NativeScriptInstance);
  160. nsi->owner = p_this;
  161. nsi->script = Ref<NativeScript>(this);
  162. #ifndef TOOLS_ENABLED
  163. if (!ScriptServer::is_scripting_enabled()) {
  164. nsi->userdata = NULL;
  165. } else {
  166. nsi->userdata = script_data->create_func.create_func((godot_object *)p_this, script_data->create_func.method_data);
  167. }
  168. #else
  169. nsi->userdata = script_data->create_func.create_func((godot_object *)p_this, script_data->create_func.method_data);
  170. #endif
  171. instance_owners.insert(p_this);
  172. return nsi;
  173. }
  174. bool NativeScript::instance_has(const Object *p_this) const {
  175. return instance_owners.has((Object *)p_this);
  176. }
  177. bool NativeScript::has_source_code() const {
  178. return false;
  179. }
  180. String NativeScript::get_source_code() const {
  181. return "";
  182. }
  183. void NativeScript::set_source_code(const String &p_code) {
  184. }
  185. Error NativeScript::reload(bool p_keep_state) {
  186. return FAILED;
  187. }
  188. bool NativeScript::has_method(const StringName &p_method) const {
  189. NativeScriptDesc *script_data = get_script_desc();
  190. while (script_data) {
  191. if (script_data->methods.has(p_method))
  192. return true;
  193. script_data = script_data->base_data;
  194. }
  195. return false;
  196. }
  197. MethodInfo NativeScript::get_method_info(const StringName &p_method) const {
  198. NativeScriptDesc *script_data = get_script_desc();
  199. if (!script_data)
  200. return MethodInfo();
  201. while (script_data) {
  202. Map<StringName, NativeScriptDesc::Method>::Element *M = script_data->methods.find(p_method);
  203. if (M)
  204. return M->get().info;
  205. script_data = script_data->base_data;
  206. }
  207. return MethodInfo();
  208. }
  209. bool NativeScript::is_tool() const {
  210. NativeScriptDesc *script_data = get_script_desc();
  211. if (script_data)
  212. return script_data->is_tool;
  213. return false;
  214. }
  215. String NativeScript::get_node_type() const {
  216. return ""; // NOTE(karroffel): uhm?
  217. }
  218. ScriptLanguage *NativeScript::get_language() const {
  219. return NativeScriptLanguage::get_singleton();
  220. }
  221. bool NativeScript::has_script_signal(const StringName &p_signal) const {
  222. NativeScriptDesc *script_data = get_script_desc();
  223. if (!script_data)
  224. return false;
  225. return script_data->signals_.has(p_signal);
  226. }
  227. void NativeScript::get_script_signal_list(List<MethodInfo> *r_signals) const {
  228. NativeScriptDesc *script_data = get_script_desc();
  229. if (!script_data)
  230. return;
  231. Set<MethodInfo> signals_;
  232. while (script_data) {
  233. for (Map<StringName, NativeScriptDesc::Signal>::Element *S = script_data->signals_.front(); S; S = S->next()) {
  234. signals_.insert(S->get().signal);
  235. }
  236. script_data = script_data->base_data;
  237. }
  238. for (Set<MethodInfo>::Element *E = signals_.front(); E; E = E->next()) {
  239. r_signals->push_back(E->get());
  240. }
  241. }
  242. bool NativeScript::get_property_default_value(const StringName &p_property, Variant &r_value) const {
  243. NativeScriptDesc *script_data = get_script_desc();
  244. if (!script_data)
  245. return false;
  246. Map<StringName, NativeScriptDesc::Property>::Element *P = script_data->properties.find(p_property);
  247. if (!P)
  248. return false;
  249. r_value = P->get().default_value;
  250. return true;
  251. }
  252. void NativeScript::update_exports() {
  253. }
  254. void NativeScript::get_script_method_list(List<MethodInfo> *p_list) const {
  255. NativeScriptDesc *script_data = get_script_desc();
  256. if (!script_data)
  257. return;
  258. Set<MethodInfo> methods;
  259. while (script_data) {
  260. for (Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.front(); E; E = E->next()) {
  261. methods.insert(E->get().info);
  262. }
  263. script_data = script_data->base_data;
  264. }
  265. for (Set<MethodInfo>::Element *E = methods.front(); E; E = E->next()) {
  266. p_list->push_back(E->get());
  267. }
  268. }
  269. void NativeScript::get_script_property_list(List<PropertyInfo> *p_list) const {
  270. NativeScriptDesc *script_data = get_script_desc();
  271. if (!script_data)
  272. return;
  273. Set<PropertyInfo> properties;
  274. while (script_data) {
  275. for (Map<StringName, NativeScriptDesc::Property>::Element *E = script_data->properties.front(); E; E = E->next()) {
  276. properties.insert(E->get().info);
  277. }
  278. script_data = script_data->base_data;
  279. }
  280. for (Set<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) {
  281. p_list->push_back(E->get());
  282. }
  283. }
  284. Variant NativeScript::_new(const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
  285. if (lib_path.empty() || class_name.empty() || library.is_null()) {
  286. r_error.error = Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL;
  287. return Variant();
  288. }
  289. NativeScriptDesc *script_data = get_script_desc();
  290. if (!script_data) {
  291. r_error.error = Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL;
  292. return Variant();
  293. }
  294. r_error.error = Variant::CallError::CALL_OK;
  295. REF ref;
  296. Object *owner = NULL;
  297. if (!(script_data->base_native_type == "")) {
  298. owner = ClassDB::instance(script_data->base_native_type);
  299. } else {
  300. owner = memnew(Reference);
  301. }
  302. Reference *r = owner->cast_to<Reference>();
  303. if (r) {
  304. ref = REF(r);
  305. }
  306. // GDScript does it like this: _create_instance(p_args, p_argcount, owner, r != NULL, r_error);
  307. // TODO(karroffel): support varargs for constructors.
  308. NativeScriptInstance *instance = (NativeScriptInstance *)instance_create(owner);
  309. owner->set_script_instance(instance);
  310. if (!instance) {
  311. if (ref.is_null()) {
  312. memdelete(owner); //no owner, sorry
  313. }
  314. return Variant();
  315. }
  316. if (ref.is_valid()) {
  317. return ref;
  318. } else {
  319. return owner;
  320. }
  321. }
  322. // TODO(karroffel): implement this
  323. NativeScript::NativeScript() {
  324. library = Ref<GDNative>();
  325. lib_path = "";
  326. class_name = "";
  327. }
  328. // TODO(karroffel): implement this
  329. NativeScript::~NativeScript() {
  330. NSL->library_script_users[lib_path].erase(this);
  331. }
  332. ////// ScriptInstance stuff
  333. #define GET_SCRIPT_DESC() script->get_script_desc()
  334. void NativeScriptInstance::_ml_call_reversed(NativeScriptDesc *script_data, const StringName &p_method, const Variant **p_args, int p_argcount) {
  335. if (script_data->base_data) {
  336. _ml_call_reversed(script_data->base_data, p_method, p_args, p_argcount);
  337. }
  338. Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.find(p_method);
  339. if (E) {
  340. godot_variant res = E->get().method.method((godot_object *)owner, E->get().method.method_data, userdata, p_argcount, (godot_variant **)p_args);
  341. godot_variant_destroy(&res);
  342. }
  343. }
  344. bool NativeScriptInstance::set(const StringName &p_name, const Variant &p_value) {
  345. NativeScriptDesc *script_data = GET_SCRIPT_DESC();
  346. while (script_data) {
  347. Map<StringName, NativeScriptDesc::Property>::Element *P = script_data->properties.find(p_name);
  348. if (P) {
  349. P->get().setter.set_func((godot_object *)owner,
  350. P->get().setter.method_data,
  351. userdata,
  352. (godot_variant *)&p_value);
  353. return true;
  354. }
  355. Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.find("_set");
  356. if (E) {
  357. Variant name = p_name;
  358. const Variant *args[2] = { &name, &p_value };
  359. E->get().method.method((godot_object *)owner,
  360. E->get().method.method_data,
  361. userdata,
  362. 2,
  363. (godot_variant **)args);
  364. return true;
  365. }
  366. script_data = script_data->base_data;
  367. }
  368. return false;
  369. }
  370. bool NativeScriptInstance::get(const StringName &p_name, Variant &r_ret) const {
  371. NativeScriptDesc *script_data = GET_SCRIPT_DESC();
  372. while (script_data) {
  373. Map<StringName, NativeScriptDesc::Property>::Element *P = script_data->properties.find(p_name);
  374. if (P) {
  375. godot_variant value;
  376. value = P->get().getter.get_func((godot_object *)owner,
  377. P->get().setter.method_data,
  378. userdata);
  379. r_ret = *(Variant *)&value;
  380. godot_variant_destroy(&value);
  381. return true;
  382. }
  383. Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.find("_get");
  384. if (E) {
  385. Variant name = p_name;
  386. const Variant *args[1] = { &name };
  387. godot_variant result;
  388. result = E->get().method.method((godot_object *)owner,
  389. E->get().method.method_data,
  390. userdata,
  391. 1,
  392. (godot_variant **)args);
  393. r_ret = *(Variant *)&result;
  394. godot_variant_destroy(&result);
  395. if (r_ret.get_type() == Variant::NIL) {
  396. return false;
  397. }
  398. return true;
  399. }
  400. script_data = script_data->base_data;
  401. }
  402. return false;
  403. }
  404. void NativeScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const {
  405. NativeScriptDesc *script_data = GET_SCRIPT_DESC();
  406. while (script_data) {
  407. Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.find("_get_property_list");
  408. if (E) {
  409. godot_variant result;
  410. result = E->get().method.method((godot_object *)owner,
  411. E->get().method.method_data,
  412. userdata,
  413. 0,
  414. NULL);
  415. Variant res = *(Variant *)&result;
  416. godot_variant_destroy(&result);
  417. if (res.get_type() != Variant::ARRAY) {
  418. ERR_EXPLAIN("_get_property_list must return an array of dictionaries");
  419. ERR_FAIL();
  420. }
  421. Array arr = res;
  422. for (int i = 0; i < arr.size(); i++) {
  423. Dictionary d = arr[i];
  424. ERR_CONTINUE(!d.has("name"));
  425. ERR_CONTINUE(!d.has("type"));
  426. PropertyInfo info;
  427. info.type = Variant::Type(d["type"].operator int64_t());
  428. ERR_CONTINUE(info.type < 0 || info.type >= Variant::VARIANT_MAX);
  429. info.name = d["name"];
  430. ERR_CONTINUE(info.name == "");
  431. if (d.has("hint")) {
  432. info.hint = PropertyHint(d["hint"].operator int64_t());
  433. }
  434. if (d.has("hint_string")) {
  435. info.hint_string = d["hint_string"];
  436. }
  437. if (d.has("usage")) {
  438. info.usage = d["usage"];
  439. }
  440. p_properties->push_back(info);
  441. }
  442. }
  443. script_data = script_data->base_data;
  444. }
  445. return;
  446. }
  447. Variant::Type NativeScriptInstance::get_property_type(const StringName &p_name, bool *r_is_valid) const {
  448. NativeScriptDesc *script_data = GET_SCRIPT_DESC();
  449. while (script_data) {
  450. Map<StringName, NativeScriptDesc::Property>::Element *P = script_data->properties.find(p_name);
  451. if (P) {
  452. *r_is_valid = true;
  453. return P->get().info.type;
  454. }
  455. script_data = script_data->base_data;
  456. }
  457. return Variant::NIL;
  458. }
  459. void NativeScriptInstance::get_method_list(List<MethodInfo> *p_list) const {
  460. script->get_method_list(p_list);
  461. }
  462. bool NativeScriptInstance::has_method(const StringName &p_method) const {
  463. return script->has_method(p_method);
  464. }
  465. Variant NativeScriptInstance::call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
  466. NativeScriptDesc *script_data = GET_SCRIPT_DESC();
  467. while (script_data) {
  468. Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.find(p_method);
  469. if (E) {
  470. godot_variant result;
  471. result = E->get().method.method((godot_object *)owner,
  472. E->get().method.method_data,
  473. userdata,
  474. p_argcount,
  475. (godot_variant **)p_args);
  476. Variant res = *(Variant *)&result;
  477. godot_variant_destroy(&result);
  478. r_error.error = Variant::CallError::CALL_OK;
  479. return res;
  480. }
  481. script_data = script_data->base_data;
  482. }
  483. r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD;
  484. return Variant();
  485. }
  486. void NativeScriptInstance::notification(int p_notification) {
  487. Variant value = p_notification;
  488. const Variant *args[1] = { &value };
  489. call_multilevel("_notification", args, 1);
  490. }
  491. Ref<Script> NativeScriptInstance::get_script() const {
  492. return script;
  493. }
  494. NativeScriptInstance::RPCMode NativeScriptInstance::get_rpc_mode(const StringName &p_method) const {
  495. NativeScriptDesc *script_data = GET_SCRIPT_DESC();
  496. while (script_data) {
  497. Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.find(p_method);
  498. if (E) {
  499. switch (E->get().rpc_mode) {
  500. case GODOT_METHOD_RPC_MODE_DISABLED:
  501. return RPC_MODE_DISABLED;
  502. case GODOT_METHOD_RPC_MODE_REMOTE:
  503. return RPC_MODE_REMOTE;
  504. case GODOT_METHOD_RPC_MODE_SYNC:
  505. return RPC_MODE_SYNC;
  506. case GODOT_METHOD_RPC_MODE_MASTER:
  507. return RPC_MODE_MASTER;
  508. case GODOT_METHOD_RPC_MODE_SLAVE:
  509. return RPC_MODE_SLAVE;
  510. default:
  511. return RPC_MODE_DISABLED;
  512. }
  513. }
  514. script_data = script_data->base_data;
  515. }
  516. return RPC_MODE_DISABLED;
  517. }
  518. // TODO(karroffel): implement this
  519. NativeScriptInstance::RPCMode NativeScriptInstance::get_rset_mode(const StringName &p_variable) const {
  520. NativeScriptDesc *script_data = GET_SCRIPT_DESC();
  521. while (script_data) {
  522. Map<StringName, NativeScriptDesc::Property>::Element *E = script_data->properties.find(p_variable);
  523. if (E) {
  524. switch (E->get().rset_mode) {
  525. case GODOT_METHOD_RPC_MODE_DISABLED:
  526. return RPC_MODE_DISABLED;
  527. case GODOT_METHOD_RPC_MODE_REMOTE:
  528. return RPC_MODE_REMOTE;
  529. case GODOT_METHOD_RPC_MODE_SYNC:
  530. return RPC_MODE_SYNC;
  531. case GODOT_METHOD_RPC_MODE_MASTER:
  532. return RPC_MODE_MASTER;
  533. case GODOT_METHOD_RPC_MODE_SLAVE:
  534. return RPC_MODE_SLAVE;
  535. default:
  536. return RPC_MODE_DISABLED;
  537. }
  538. }
  539. script_data = script_data->base_data;
  540. }
  541. return RPC_MODE_DISABLED;
  542. }
  543. ScriptLanguage *NativeScriptInstance::get_language() {
  544. return NativeScriptLanguage::get_singleton();
  545. }
  546. void NativeScriptInstance::call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount) {
  547. NativeScriptDesc *script_data = GET_SCRIPT_DESC();
  548. while (script_data) {
  549. Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.find(p_method);
  550. if (E) {
  551. godot_variant res = E->get().method.method((godot_object *)owner,
  552. E->get().method.method_data,
  553. userdata,
  554. p_argcount,
  555. (godot_variant **)p_args);
  556. godot_variant_destroy(&res);
  557. }
  558. script_data = script_data->base_data;
  559. }
  560. }
  561. void NativeScriptInstance::call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount) {
  562. NativeScriptDesc *script_data = GET_SCRIPT_DESC();
  563. if (script_data) {
  564. _ml_call_reversed(script_data, p_method, p_args, p_argcount);
  565. }
  566. }
  567. NativeScriptInstance::~NativeScriptInstance() {
  568. NativeScriptDesc *script_data = GET_SCRIPT_DESC();
  569. if (!script_data)
  570. return;
  571. script_data->destroy_func.destroy_func((godot_object *)owner, script_data->destroy_func.method_data, userdata);
  572. if (owner) {
  573. script->instance_owners.erase(owner);
  574. }
  575. }
  576. ////// ScriptingLanguage stuff
  577. NativeScriptLanguage *NativeScriptLanguage::singleton;
  578. extern "C" void _native_script_hook();
  579. void NativeScriptLanguage::_hacky_api_anchor() {
  580. _native_script_hook();
  581. }
  582. void NativeScriptLanguage::_unload_stuff() {
  583. for (Map<String, Map<StringName, NativeScriptDesc> >::Element *L = library_classes.front(); L; L = L->next()) {
  584. for (Map<StringName, NativeScriptDesc>::Element *C = L->get().front(); C; C = C->next()) {
  585. // free property stuff first
  586. for (Map<StringName, NativeScriptDesc::Property>::Element *P = C->get().properties.front(); P; P = P->next()) {
  587. if (P->get().getter.free_func)
  588. P->get().getter.free_func(P->get().getter.method_data);
  589. if (P->get().setter.free_func)
  590. P->get().setter.free_func(P->get().setter.method_data);
  591. }
  592. // free method stuff
  593. for (Map<StringName, NativeScriptDesc::Method>::Element *M = C->get().methods.front(); M; M = M->next()) {
  594. if (M->get().method.free_func)
  595. M->get().method.free_func(M->get().method.method_data);
  596. }
  597. // free constructor/destructor
  598. if (C->get().create_func.free_func)
  599. C->get().create_func.free_func(C->get().create_func.method_data);
  600. if (C->get().destroy_func.free_func)
  601. C->get().destroy_func.free_func(C->get().destroy_func.method_data);
  602. }
  603. }
  604. }
  605. NativeScriptLanguage::NativeScriptLanguage() {
  606. NativeScriptLanguage::singleton = this;
  607. }
  608. // TODO(karroffel): implement this
  609. NativeScriptLanguage::~NativeScriptLanguage() {
  610. _unload_stuff();
  611. for (Map<String, Ref<GDNative> >::Element *L = NSL->library_gdnatives.front(); L; L = L->next()) {
  612. L->get()->terminate();
  613. NSL->library_classes.clear();
  614. NSL->library_gdnatives.clear();
  615. NSL->library_script_users.clear();
  616. }
  617. }
  618. String NativeScriptLanguage::get_name() const {
  619. return "NativeScript";
  620. }
  621. void _add_reload_node() {
  622. #ifdef TOOLS_ENABLED
  623. NativeReloadNode *rn = memnew(NativeReloadNode);
  624. EditorNode::get_singleton()->add_child(rn);
  625. #endif
  626. }
  627. // TODO(karroffel): implement this
  628. void NativeScriptLanguage::init() {
  629. #if defined(TOOLS_ENABLED) && defined(DEBUG_METHODS_ENABLED)
  630. List<String> args = OS::get_singleton()->get_cmdline_args();
  631. List<String>::Element *E = args.find("--gdnative-generate-json-api");
  632. if (E && E->next()) {
  633. if (generate_c_api(E->next()->get()) != OK) {
  634. ERR_PRINT("Failed to generate C API\n");
  635. }
  636. }
  637. #endif
  638. #ifdef TOOLS_ENABLED
  639. EditorNode::add_init_callback(&_add_reload_node);
  640. #endif
  641. }
  642. String NativeScriptLanguage::get_type() const {
  643. return "NativeScript";
  644. }
  645. String NativeScriptLanguage::get_extension() const {
  646. return "gdns";
  647. }
  648. Error NativeScriptLanguage::execute_file(const String &p_path) {
  649. return OK; // Qué?
  650. }
  651. void NativeScriptLanguage::finish() {
  652. _unload_stuff();
  653. }
  654. void NativeScriptLanguage::get_reserved_words(List<String> *p_words) const {
  655. }
  656. void NativeScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) const {
  657. }
  658. void NativeScriptLanguage::get_string_delimiters(List<String> *p_delimiters) const {
  659. }
  660. // TODO(karroffel): implement this
  661. Ref<Script> NativeScriptLanguage::get_template(const String &p_class_name, const String &p_base_class_name) const {
  662. NativeScript *s = memnew(NativeScript);
  663. s->set_class_name(p_class_name);
  664. // TODO(karroffel): use p_base_class_name
  665. return Ref<NativeScript>(s);
  666. }
  667. bool NativeScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions) const {
  668. return false;
  669. }
  670. Script *NativeScriptLanguage::create_script() const {
  671. NativeScript *script = memnew(NativeScript);
  672. return script;
  673. }
  674. bool NativeScriptLanguage::has_named_classes() const {
  675. return true;
  676. }
  677. int NativeScriptLanguage::find_function(const String &p_function, const String &p_code) const {
  678. return -1;
  679. }
  680. String NativeScriptLanguage::make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const {
  681. return "";
  682. }
  683. void NativeScriptLanguage::auto_indent_code(String &p_code, int p_from_line, int p_to_line) const {
  684. }
  685. void NativeScriptLanguage::add_global_constant(const StringName &p_variable, const Variant &p_value) {
  686. }
  687. // Debugging stuff here. Not used for now.
  688. String NativeScriptLanguage::debug_get_error() const {
  689. return "";
  690. }
  691. int NativeScriptLanguage::debug_get_stack_level_count() const {
  692. return -1;
  693. }
  694. int NativeScriptLanguage::debug_get_stack_level_line(int p_level) const {
  695. return -1;
  696. }
  697. String NativeScriptLanguage::debug_get_stack_level_function(int p_level) const {
  698. return "";
  699. }
  700. String NativeScriptLanguage::debug_get_stack_level_source(int p_level) const {
  701. return "";
  702. }
  703. void NativeScriptLanguage::debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {
  704. }
  705. void NativeScriptLanguage::debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {
  706. }
  707. void NativeScriptLanguage::debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {
  708. }
  709. String NativeScriptLanguage::debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems, int p_max_depth) {
  710. return "";
  711. }
  712. // Debugging stuff end.
  713. void NativeScriptLanguage::reload_all_scripts() {
  714. }
  715. void NativeScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload) {
  716. }
  717. void NativeScriptLanguage::get_recognized_extensions(List<String> *p_extensions) const {
  718. p_extensions->push_back("gdns");
  719. }
  720. void NativeScriptLanguage::get_public_functions(List<MethodInfo> *p_functions) const {
  721. }
  722. void NativeScriptLanguage::get_public_constants(List<Pair<String, Variant> > *p_constants) const {
  723. }
  724. void NativeScriptLanguage::profiling_start() {
  725. }
  726. void NativeScriptLanguage::profiling_stop() {
  727. }
  728. int NativeScriptLanguage::profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max) {
  729. return -1;
  730. }
  731. int NativeScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max) {
  732. return -1;
  733. }
  734. void NativeReloadNode::_bind_methods() {
  735. ClassDB::bind_method(D_METHOD("_notification"), &NativeReloadNode::_notification);
  736. }
  737. void NativeReloadNode::_notification(int p_what) {
  738. #ifdef TOOLS_ENABLED
  739. switch (p_what) {
  740. case MainLoop::NOTIFICATION_WM_FOCUS_OUT: {
  741. print_line("unload");
  742. NSL->_unload_stuff();
  743. for (Map<String, Ref<GDNative> >::Element *L = NSL->library_gdnatives.front(); L; L = L->next()) {
  744. L->get()->terminate();
  745. NSL->library_classes.erase(L->key());
  746. }
  747. } break;
  748. case MainLoop::NOTIFICATION_WM_FOCUS_IN: {
  749. print_line("load");
  750. Set<StringName> libs_to_remove;
  751. for (Map<String, Ref<GDNative> >::Element *L = NSL->library_gdnatives.front(); L; L = L->next()) {
  752. if (!L->get()->initialize()) {
  753. libs_to_remove.insert(L->key());
  754. continue;
  755. }
  756. NSL->library_classes.insert(L->key(), Map<StringName, NativeScriptDesc>());
  757. void *args[1] = {
  758. (void *)&L->key()
  759. };
  760. // here the library registers all the classes and stuff.
  761. L->get()->call_native_raw(NSL->_init_call_type,
  762. NSL->_init_call_name,
  763. NULL,
  764. 1,
  765. args,
  766. NULL);
  767. for (Map<String, Set<NativeScript *> >::Element *U = NSL->library_script_users.front(); U; U = U->next()) {
  768. for (Set<NativeScript *>::Element *S = U->get().front(); S; S = S->next()) {
  769. NativeScript *script = S->get();
  770. if (script->placeholders.size() == 0)
  771. continue;
  772. for (Set<PlaceHolderScriptInstance *>::Element *P = script->placeholders.front(); P; P = P->next()) {
  773. script->_update_placeholder(P->get());
  774. }
  775. }
  776. }
  777. }
  778. for (Set<StringName>::Element *R = libs_to_remove.front(); R; R = R->next()) {
  779. NSL->library_gdnatives.erase(R->get());
  780. }
  781. /*
  782. for (Set<NativeLibrary *>::Element *L = libs_to_reload.front(); L; L = L->next()) {
  783. GDNativeLibrary *lib = L->get()->dllib;
  784. lib->_terminate();
  785. lib->_initialize();
  786. // update placeholders (if any)
  787. Set<GDNativeScript *> scripts;
  788. for (Set<GDNativeScript *>::Element *S = GDNativeScriptLanguage::get_singleton()->script_list.front(); S; S = S->next()) {
  789. if (lib->native_library->scripts.has(S->get()->get_script_name())) {
  790. GDNativeScript *script = S->get();
  791. script->script_data = lib->get_script_data(script->get_script_name());
  792. scripts.insert(script);
  793. }
  794. }
  795. for (Set<GDNativeScript *>::Element *S = scripts.front(); S; S = S->next()) {
  796. GDNativeScript *script = S->get();
  797. if (script->placeholders.size() == 0)
  798. continue;
  799. for (Set<PlaceHolderScriptInstance *>::Element *P = script->placeholders.front(); P; P = P->next()) {
  800. PlaceHolderScriptInstance *p = P->get();
  801. script->_update_placeholder(p);
  802. }
  803. }
  804. }
  805. */
  806. } break;
  807. default: {
  808. };
  809. }
  810. #endif
  811. }
  812. RES ResourceFormatLoaderNativeScript::load(const String &p_path, const String &p_original_path, Error *r_error) {
  813. ResourceFormatLoaderText rsflt;
  814. return rsflt.load(p_path, p_original_path, r_error);
  815. }
  816. void ResourceFormatLoaderNativeScript::get_recognized_extensions(List<String> *p_extensions) const {
  817. p_extensions->push_back("gdns");
  818. }
  819. bool ResourceFormatLoaderNativeScript::handles_type(const String &p_type) const {
  820. return (p_type == "Script" || p_type == "NativeScript");
  821. }
  822. String ResourceFormatLoaderNativeScript::get_resource_type(const String &p_path) const {
  823. String el = p_path.get_extension().to_lower();
  824. if (el == "gdns")
  825. return "NativeScript";
  826. return "";
  827. }
  828. Error ResourceFormatSaverNativeScript::save(const String &p_path, const RES &p_resource, uint32_t p_flags) {
  829. ResourceFormatSaverText rfst;
  830. return rfst.save(p_path, p_resource, p_flags);
  831. }
  832. bool ResourceFormatSaverNativeScript::recognize(const RES &p_resource) const {
  833. return p_resource->cast_to<NativeScript>() != NULL;
  834. }
  835. void ResourceFormatSaverNativeScript::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const {
  836. if (p_resource->cast_to<NativeScript>()) {
  837. p_extensions->push_back("gdns");
  838. }
  839. }