dl_script.cpp 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048
  1. /*************************************************************************/
  2. /* dl_script.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 "dl_script.h"
  30. #include "global_config.h"
  31. #include "global_constants.h"
  32. #include "io/file_access_encrypted.h"
  33. #include "os/file_access.h"
  34. #include "os/os.h"
  35. #include "scene/resources/scene_format_text.h"
  36. #ifdef TOOLS_ENABLED
  37. // #include "editor/editor_import_export.h"
  38. #endif
  39. #if defined(TOOLS_ENABLED) && defined(DEBUG_METHODS_ENABLED)
  40. #include "api_generator.h"
  41. #endif
  42. // Script
  43. bool DLScript::can_instance() const {
  44. #ifdef DLSCRIPT_EDITOR_FEATURES
  45. return script_data || (!is_tool() && !ScriptServer::is_scripting_enabled());
  46. #else
  47. // allow defaultlibrary without editor features
  48. if (!library.is_valid()) {
  49. String path = GLOBAL_GET("dlscript/default_dllibrary");
  50. RES lib = ResourceLoader::load(path);
  51. if (lib.is_valid() && lib->cast_to<DLLibrary>()) {
  52. return true;
  53. }
  54. }
  55. return script_data;
  56. #endif
  57. //return script_data || (!tool && !ScriptServer::is_scripting_enabled());
  58. // change to true enable in editor stuff.
  59. }
  60. Ref<Script> DLScript::get_base_script() const {
  61. Ref<DLScript> base_script;
  62. base_script->library = library;
  63. base_script->script_data = script_data;
  64. base_script->script_name = script_data->base;
  65. return base_script;
  66. }
  67. StringName DLScript::get_instance_base_type() const {
  68. return script_data->base_native_type;
  69. }
  70. ScriptInstance *DLScript::instance_create(Object *p_this) {
  71. #ifdef TOOLS_ENABLED
  72. // find a good way to initialize stuff in the editor
  73. #ifdef DLSCRIPT_EDITOR_FEATURES
  74. if (!ScriptServer::is_scripting_enabled() && !is_tool()) {
  75. // placeholder, for nodes. But for tools we want the real thing
  76. PlaceHolderScriptInstance *sins = memnew(PlaceHolderScriptInstance(DLScriptLanguage::singleton, Ref<Script>((Script *)this), p_this));
  77. placeholders.insert(sins);
  78. List<PropertyInfo> pinfo;
  79. Map<StringName, Variant> values;
  80. if (!library.is_valid())
  81. return sins;
  82. if (!library->library_handle) {
  83. Error err = library->_initialize_handle(true);
  84. if (err != OK) {
  85. return sins;
  86. }
  87. }
  88. if (!script_data) {
  89. script_data = library->get_script_data(script_name);
  90. }
  91. if (script_data)
  92. script_data->create_func.create_func((godot_object *)p_this, script_data->create_func.method_data);
  93. if (script_data) {
  94. for (Map<StringName, DLScriptData::Property>::Element *E = script_data->properties.front(); E; E = E->next()) {
  95. PropertyInfo p = E->get().info;
  96. p.name = String(E->key());
  97. pinfo.push_back(p);
  98. values[p.name] = E->get().default_value;
  99. }
  100. }
  101. sins->update(pinfo, values);
  102. return sins;
  103. }
  104. #endif
  105. #endif
  106. if (!library.is_valid()) {
  107. String path = GLOBAL_GET("dlscript/default_dllibrary");
  108. RES lib = ResourceLoader::load(path);
  109. if (lib.is_valid() && lib->cast_to<DLLibrary>()) {
  110. set_library(lib);
  111. }
  112. }
  113. DLInstance *new_instance = memnew(DLInstance);
  114. new_instance->owner = p_this;
  115. new_instance->script = Ref<DLScript>(this);
  116. #ifndef DLSCRIPT_EDITOR_FEATURES
  117. if (!ScriptServer::is_scripting_enabled()) {
  118. new_instance->userdata = 0;
  119. } else {
  120. new_instance->userdata = script_data->create_func.create_func((godot_object *)p_this, script_data->create_func.method_data);
  121. }
  122. #else
  123. new_instance->userdata = script_data->create_func.create_func((godot_object *)p_this, script_data->create_func.method_data);
  124. #endif
  125. instances.insert(p_this);
  126. return new_instance;
  127. }
  128. bool DLScript::instance_has(const Object *p_this) const {
  129. return instances.has((Object *)p_this); // TODO
  130. }
  131. bool DLScript::has_source_code() const {
  132. return false;
  133. }
  134. String DLScript::get_source_code() const {
  135. return "";
  136. }
  137. Error DLScript::reload(bool p_keep_state) {
  138. return FAILED;
  139. }
  140. bool DLScript::has_method(const StringName &p_method) const {
  141. if (!script_data)
  142. return false;
  143. return script_data->methods.has(p_method);
  144. }
  145. MethodInfo DLScript::get_method_info(const StringName &p_method) const {
  146. if (!script_data)
  147. return MethodInfo();
  148. ERR_FAIL_COND_V(!script_data->methods.has(p_method), MethodInfo());
  149. return script_data->methods[p_method].info;
  150. }
  151. void DLScript::get_script_method_list(List<MethodInfo> *p_list) const {
  152. if (!script_data) return;
  153. for (Map<StringName, DLScriptData::Method>::Element *E = script_data->methods.front(); E; E = E->next()) {
  154. p_list->push_back(E->get().info);
  155. }
  156. }
  157. void DLScript::get_script_property_list(List<PropertyInfo> *p_list) const {
  158. if (!script_data) return;
  159. for (Map<StringName, DLScriptData::Property>::Element *E = script_data->properties.front(); E; E = E->next()) {
  160. p_list->push_back(E->get().info);
  161. }
  162. }
  163. bool DLScript::get_property_default_value(const StringName &p_property, Variant &r_value) const {
  164. if (!script_data) return false;
  165. if (script_data->properties.has(p_property)) {
  166. r_value = script_data->properties[p_property].default_value;
  167. return true;
  168. }
  169. return false;
  170. }
  171. bool DLScript::is_tool() const {
  172. ERR_FAIL_COND_V(!script_data, false);
  173. return script_data->is_tool;
  174. }
  175. String DLScript::get_node_type() const {
  176. return ""; // ?
  177. }
  178. ScriptLanguage *DLScript::get_language() const {
  179. return DLScriptLanguage::singleton;
  180. }
  181. bool DLScript::has_script_signal(const StringName &p_signal) const {
  182. if (!script_data)
  183. return false;
  184. return script_data->signals_.has(p_signal);
  185. }
  186. void DLScript::get_script_signal_list(List<MethodInfo> *r_signals) const {
  187. if (!script_data)
  188. return;
  189. for (Map<StringName, DLScriptData::Signal>::Element *S = script_data->signals_.front(); S; S = S->next()) {
  190. r_signals->push_back(S->get().signal);
  191. }
  192. }
  193. Ref<DLLibrary> DLScript::get_library() const {
  194. return library;
  195. }
  196. void DLScript::set_library(Ref<DLLibrary> p_library) {
  197. library = p_library;
  198. #ifdef TOOLS_ENABLED
  199. if (!ScriptServer::is_scripting_enabled())
  200. return;
  201. #endif
  202. if (library.is_valid()) {
  203. Error initalize_status = library->_initialize_handle(!ScriptServer::is_scripting_enabled());
  204. ERR_FAIL_COND(initalize_status != OK);
  205. if (script_name) {
  206. script_data = library->get_script_data(script_name);
  207. ERR_FAIL_COND(!script_data);
  208. }
  209. }
  210. }
  211. StringName DLScript::get_script_name() const {
  212. return script_name;
  213. }
  214. void DLScript::set_script_name(StringName p_script_name) {
  215. script_name = p_script_name;
  216. if (library.is_valid()) {
  217. script_data = library->get_script_data(script_name);
  218. ERR_FAIL_COND(!script_data);
  219. }
  220. }
  221. void DLScript::_bind_methods() {
  222. ClassDB::bind_method(D_METHOD("get_library"), &DLScript::get_library);
  223. ClassDB::bind_method(D_METHOD("set_library", "library"), &DLScript::set_library);
  224. ClassDB::bind_method(D_METHOD("get_script_name"), &DLScript::get_script_name);
  225. ClassDB::bind_method(D_METHOD("set_script_name", "script_name"), &DLScript::set_script_name);
  226. ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "library", PROPERTY_HINT_RESOURCE_TYPE, "DLLibrary"), "set_library", "get_library");
  227. ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "script_name"), "set_script_name", "get_script_name");
  228. }
  229. DLScript::DLScript() {
  230. script_data = NULL;
  231. }
  232. DLScript::~DLScript() {
  233. //hmm
  234. }
  235. // Library
  236. DLLibrary *DLLibrary::currently_initialized_library = NULL;
  237. DLLibrary *DLLibrary::get_currently_initialized_library() {
  238. return currently_initialized_library;
  239. }
  240. static const char *_dl_platforms_info[] = {
  241. "|unix|so|Unix",
  242. "unix|x11|so|X11",
  243. "unix|server|so|Server",
  244. "unix|android|so|Android",
  245. "unix|blackberry|so|Blackberry 10",
  246. "unix|haiku|so|Haiku", // Right?
  247. "|mac|dynlib|Mac",
  248. "mac|ios|dynlib|iOS",
  249. "mac|osx|dynlib|OSX",
  250. "|html5|js|HTML5",
  251. "|windows|dll|Windows",
  252. "windows|uwp|dll|UWP",
  253. NULL // Finishing condition
  254. };
  255. void DLLibrary::set_platform_file(StringName p_platform, String p_file) {
  256. if (p_file.empty()) {
  257. platform_files.erase(p_platform);
  258. } else {
  259. platform_files[p_platform] = p_file;
  260. }
  261. }
  262. String DLLibrary::get_platform_file(StringName p_platform) const {
  263. if (platform_files.has(p_platform)) {
  264. return platform_files[p_platform];
  265. } else {
  266. return "";
  267. }
  268. }
  269. Error DLLibrary::_initialize_handle(bool p_in_editor) {
  270. _THREAD_SAFE_METHOD_
  271. void *_library_handle;
  272. // Get the file
  273. const String platform_name = OS::get_singleton()->get_name();
  274. String platform_file("");
  275. char **platform_info = (char **)_dl_platforms_info;
  276. if (platform_files.has(platform_name.to_lower())) {
  277. platform_file = platform_files[platform_name.to_lower()];
  278. }
  279. while (*platform_info) {
  280. String platform_info_string(*platform_info);
  281. if (platform_name == platform_info_string.get_slicec('|', 3)) {
  282. String platform_key = platform_info_string.get_slicec('|', 1);
  283. String fallback_platform_key = platform_info_string.get_slicec('|', 0);
  284. if (platform_files.has(platform_key)) {
  285. platform_file = platform_files[platform_key];
  286. } else if (!fallback_platform_key.empty() && platform_files.has(fallback_platform_key)) {
  287. platform_file = platform_files[fallback_platform_key];
  288. } else {
  289. return ERR_UNAVAILABLE;
  290. }
  291. }
  292. platform_info++;
  293. }
  294. ERR_FAIL_COND_V(platform_file == "", ERR_DOES_NOT_EXIST);
  295. library_path = GlobalConfig::get_singleton()->globalize_path(platform_file);
  296. if (DLScriptLanguage::get_singleton()->is_library_initialized(library_path)) {
  297. *this = *DLScriptLanguage::get_singleton()->get_library_dllibrary(library_path);
  298. return OK;
  299. }
  300. // Open the file
  301. Error error;
  302. error = OS::get_singleton()->open_dynamic_library(library_path, _library_handle);
  303. if (error) return error;
  304. ERR_FAIL_COND_V(!_library_handle, ERR_BUG);
  305. // Get the method
  306. void *library_init;
  307. error = OS::get_singleton()->get_dynamic_library_symbol_handle(_library_handle, DLScriptLanguage::get_init_symbol_name(), library_init);
  308. if (error) return error;
  309. ERR_FAIL_COND_V(!library_init, ERR_BUG);
  310. DLLibrary::currently_initialized_library = this;
  311. void (*library_init_fpointer)(godot_dlscript_init_options *) = (void (*)(godot_dlscript_init_options *))library_init;
  312. godot_dlscript_init_options options;
  313. options.in_editor = p_in_editor;
  314. options.core_api_hash = ClassDB::get_api_hash(ClassDB::API_CORE);
  315. options.editor_api_hash = ClassDB::get_api_hash(ClassDB::API_EDITOR);
  316. options.no_api_hash = ClassDB::get_api_hash(ClassDB::API_NONE);
  317. library_init_fpointer(&options); // Catch errors?
  318. /*{
  319. ERR_EXPLAIN("Couldn't initialize library");
  320. ERR_FAIL_V(ERR_SCRIPT_FAILED);
  321. }*/
  322. DLLibrary::currently_initialized_library = NULL;
  323. library_handle = _library_handle;
  324. DLScriptLanguage::get_singleton()->set_library_initialized(library_path, this);
  325. return OK;
  326. }
  327. Error DLLibrary::_free_handle(bool p_in_editor) {
  328. ERR_FAIL_COND_V(!library_handle, ERR_BUG);
  329. if (!DLScriptLanguage::get_singleton()->is_library_initialized(library_path)) {
  330. OS::get_singleton()->close_dynamic_library(library_handle);
  331. library_handle = 0;
  332. return OK;
  333. }
  334. Error error = OK;
  335. void *library_terminate;
  336. error = OS::get_singleton()->get_dynamic_library_symbol_handle(library_handle, DLScriptLanguage::get_terminate_symbol_name(), library_terminate);
  337. if (error)
  338. return OK; // no terminate? okay, not that important lol
  339. void (*library_terminate_pointer)(godot_dlscript_terminate_options *) = (void (*)(godot_dlscript_terminate_options *))library_terminate;
  340. godot_dlscript_terminate_options options;
  341. options.in_editor = p_in_editor;
  342. library_terminate_pointer(&options);
  343. DLScriptLanguage::get_singleton()->set_library_uninitialized(library_path);
  344. OS::get_singleton()->close_dynamic_library(library_handle);
  345. library_handle = 0;
  346. return OK;
  347. }
  348. void DLLibrary::_register_script(const StringName p_name, const StringName p_base, godot_instance_create_func p_instance_func, godot_instance_destroy_func p_destroy_func) {
  349. ERR_FAIL_COND(scripts.has(p_name));
  350. DLScriptData *s = memnew(DLScriptData);
  351. s->base = p_base;
  352. s->create_func = p_instance_func;
  353. s->destroy_func = p_destroy_func;
  354. Map<StringName, DLScriptData *>::Element *E = scripts.find(p_base);
  355. if (E) {
  356. s->base_data = E->get();
  357. s->base_native_type = s->base_data->base_native_type;
  358. } else {
  359. if (!ClassDB::class_exists(p_base)) {
  360. memdelete(s);
  361. ERR_EXPLAIN("Invalid base for registered type '" + p_name + "'");
  362. ERR_FAIL();
  363. }
  364. s->base_native_type = p_base;
  365. }
  366. scripts.insert(p_name, s);
  367. }
  368. void DLLibrary::_register_tool_script(const StringName p_name, const StringName p_base, godot_instance_create_func p_instance_func, godot_instance_destroy_func p_destroy_func) {
  369. ERR_FAIL_COND(scripts.has(p_name));
  370. DLScriptData *s = memnew(DLScriptData);
  371. s->base = p_base;
  372. s->create_func = p_instance_func;
  373. s->destroy_func = p_destroy_func;
  374. s->is_tool = true;
  375. Map<StringName, DLScriptData *>::Element *E = scripts.find(p_base);
  376. if (E) {
  377. s->base_data = E->get();
  378. s->base_native_type = s->base_data->base_native_type;
  379. } else {
  380. if (!ClassDB::class_exists(p_base)) {
  381. memdelete(s);
  382. ERR_EXPLAIN("Invalid base for registered type '" + p_name + "'");
  383. ERR_FAIL();
  384. }
  385. s->base_native_type = p_base;
  386. }
  387. scripts.insert(p_name, s);
  388. }
  389. void DLLibrary::_register_script_method(const StringName p_name, const StringName p_method, godot_method_attributes p_attr, godot_instance_method p_func, MethodInfo p_info) {
  390. ERR_FAIL_COND(!scripts.has(p_name));
  391. p_info.name = p_method;
  392. DLScriptData::Method method;
  393. method = DLScriptData::Method(p_func, p_info, p_attr.rpc_type);
  394. scripts[p_name]->methods.insert(p_method, method);
  395. }
  396. void DLLibrary::_register_script_property(const StringName p_name, const String p_path, godot_property_attributes *p_attr, godot_property_set_func p_setter, godot_property_get_func p_getter) {
  397. ERR_FAIL_COND(!scripts.has(p_name));
  398. DLScriptData::Property p;
  399. PropertyInfo pi;
  400. pi.name = p_path;
  401. if (p_attr != NULL) {
  402. pi = PropertyInfo((Variant::Type)p_attr->type, p_path, (PropertyHint)p_attr->hint, *(String *)&p_attr->hint_string, p_attr->usage);
  403. p = DLScriptData::Property(p_setter, p_getter, pi, *(Variant *)&p_attr->default_value, p_attr->rset_type);
  404. }
  405. scripts[p_name]->properties.insert(p_path, p);
  406. }
  407. void DLLibrary::_register_script_signal(const StringName p_name, const godot_signal *p_signal) {
  408. ERR_FAIL_COND(!scripts.has(p_name));
  409. ERR_FAIL_COND(!p_signal);
  410. DLScriptData::Signal signal;
  411. signal.signal.name = *(String *)&p_signal->name;
  412. {
  413. List<PropertyInfo> arguments;
  414. for (int i = 0; i < p_signal->num_args; i++) {
  415. PropertyInfo info;
  416. godot_signal_argument attrib = p_signal->args[i];
  417. String *name = (String *)&attrib.name;
  418. info.name = *name;
  419. info.type = (Variant::Type)attrib.type;
  420. info.hint = (PropertyHint)attrib.hint;
  421. info.hint_string = *(String *)&attrib.hint_string;
  422. info.usage = attrib.usage;
  423. arguments.push_back(info);
  424. }
  425. signal.signal.arguments = arguments;
  426. }
  427. {
  428. Vector<Variant> default_arguments;
  429. for (int i = 0; i < p_signal->num_default_args; i++) {
  430. Variant *v;
  431. godot_signal_argument attrib = p_signal->args[i];
  432. v = (Variant *)&attrib.default_value;
  433. default_arguments.push_back(*v);
  434. }
  435. signal.signal.default_arguments = default_arguments;
  436. }
  437. scripts[p_name]->signals_.insert(*(String *)&p_signal->name, signal);
  438. }
  439. DLScriptData *DLLibrary::get_script_data(const StringName p_name) {
  440. if (!scripts.has(p_name)) {
  441. if (DLScriptLanguage::get_singleton()->is_library_initialized(library_path)) {
  442. _update_library(*DLScriptLanguage::get_singleton()->get_library_dllibrary(library_path));
  443. }
  444. ERR_FAIL_COND_V(!scripts.has(p_name), NULL);
  445. }
  446. return scripts[p_name];
  447. }
  448. bool DLLibrary::_set(const StringName &p_name, const Variant &p_value) {
  449. String name = p_name;
  450. if (name.begins_with("platform/")) {
  451. set_platform_file(name.get_slice("/", 1), p_value);
  452. return true;
  453. }
  454. return false;
  455. }
  456. bool DLLibrary::_get(const StringName &p_name, Variant &r_ret) const {
  457. String name = p_name;
  458. if (name.begins_with("platform/")) {
  459. r_ret = get_platform_file(name.get_slice("/", 1));
  460. return true;
  461. }
  462. return false;
  463. }
  464. void DLLibrary::_get_property_list(List<PropertyInfo> *p_list) const {
  465. char **platform_info = (char **)_dl_platforms_info;
  466. Set<String> registered_platform_names;
  467. {
  468. List<StringName> ep;
  469. // ep.push_back("X11");
  470. // EditorImportExport::get_singleton()->get_export_platforms(&ep);
  471. for (List<StringName>::Element *E = ep.front(); E; E = E->next()) {
  472. registered_platform_names.insert(String(E->get()).to_lower());
  473. }
  474. }
  475. while (*platform_info) {
  476. String platform_info_string(*platform_info);
  477. String fallback_platform_key = platform_info_string.get_slicec('|', 0);
  478. String platform_key = platform_info_string.get_slicec('|', 1);
  479. String platform_extension = platform_info_string.get_slicec('|', 2);
  480. String platform_name = platform_info_string.get_slicec('|', 3);
  481. registered_platform_names.erase(platform_name);
  482. if (fallback_platform_key.empty()) {
  483. p_list->push_back(PropertyInfo(Variant::STRING, "platform/" + platform_key, PROPERTY_HINT_FILE, "*." + platform_extension));
  484. } else {
  485. if (platform_files.has(platform_key)) {
  486. p_list->push_back(PropertyInfo(Variant::STRING, "platform/" + platform_key, PROPERTY_HINT_FILE, "*." + platform_extension, PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CHECKABLE | PROPERTY_USAGE_CHECKED));
  487. } else {
  488. p_list->push_back(PropertyInfo(Variant::STRING, "platform/" + platform_key, PROPERTY_HINT_FILE, "*." + platform_extension, PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CHECKABLE));
  489. }
  490. }
  491. platform_info++;
  492. }
  493. while (registered_platform_names.size()) {
  494. const String platform_name = registered_platform_names.front()->get();
  495. registered_platform_names.erase(platform_name);
  496. p_list->push_back(PropertyInfo(Variant::STRING, "platform/" + platform_name.to_lower(), PROPERTY_HINT_FILE, "*"));
  497. }
  498. }
  499. void DLLibrary::_notification(int what) {
  500. // TODO
  501. }
  502. void DLLibrary::_bind_methods() {
  503. ClassDB::bind_method(D_METHOD("set_platform_file", "platform", "file"), &DLLibrary::set_platform_file);
  504. ClassDB::bind_method(D_METHOD("get_platform_file", "platform"), &DLLibrary::get_platform_file);
  505. }
  506. DLLibrary::DLLibrary() {
  507. library_handle = NULL;
  508. }
  509. DLLibrary::~DLLibrary() {
  510. for (Map<StringName, DLScriptData *>::Element *E = scripts.front(); E; E = E->next()) {
  511. for (Map<StringName, DLScriptData::Method>::Element *M = E->get()->methods.front(); M; M = M->next()) {
  512. if (M->get().method.free_func) {
  513. M->get().method.free_func(M->get().method.method_data);
  514. }
  515. }
  516. memdelete(E->get());
  517. }
  518. if (library_handle) {
  519. bool in_editor = false;
  520. #ifdef TOOLS_ENABLED
  521. in_editor = !ScriptServer::is_scripting_enabled();
  522. #endif
  523. _free_handle(in_editor);
  524. }
  525. }
  526. // Instance
  527. bool DLInstance::set(const StringName &p_name, const Variant &p_value) {
  528. if (!script->script_data)
  529. return false;
  530. if (script->script_data->properties.has(p_name)) {
  531. script->script_data->properties[p_name].setter.set_func((godot_object *)owner, script->script_data->properties[p_name].setter.method_data, userdata, *(godot_variant *)&p_value);
  532. return true;
  533. }
  534. return false;
  535. }
  536. bool DLInstance::get(const StringName &p_name, Variant &r_ret) const {
  537. if (!script->script_data)
  538. return false;
  539. if (script->script_data->properties.has(p_name)) {
  540. godot_variant value = script->script_data->properties[p_name].getter.get_func((godot_object *)owner, script->script_data->properties[p_name].getter.method_data, userdata);
  541. r_ret = *(Variant *)&value;
  542. return true;
  543. }
  544. return false;
  545. }
  546. void DLInstance::get_property_list(List<PropertyInfo> *p_properties) const {
  547. script->get_script_property_list(p_properties);
  548. // TODO: dynamic properties
  549. }
  550. Variant::Type DLInstance::get_property_type(const StringName &p_name, bool *r_is_valid) const {
  551. if (script->script_data->properties.has(p_name)) {
  552. *r_is_valid = true;
  553. return script->script_data->properties[p_name].info.type;
  554. }
  555. *r_is_valid = false;
  556. return Variant::NIL;
  557. }
  558. void DLInstance::get_method_list(List<MethodInfo> *p_list) const {
  559. script->get_script_method_list(p_list);
  560. }
  561. bool DLInstance::has_method(const StringName &p_method) const {
  562. return script->has_method(p_method);
  563. }
  564. Variant DLInstance::call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
  565. // TODO: validated methods & errors
  566. DLScriptData *data_ptr = script->script_data;
  567. while (data_ptr) {
  568. Map<StringName, DLScriptData::Method>::Element *E = data_ptr->methods.find(p_method);
  569. if (E) {
  570. godot_variant result = E->get().method.method((godot_object *)owner, E->get().method.method_data, userdata, p_argcount, (godot_variant **)p_args);
  571. return *(Variant *)&result;
  572. }
  573. data_ptr = data_ptr->base_data;
  574. }
  575. r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD;
  576. return Variant();
  577. }
  578. void DLInstance::call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount) {
  579. // TODO: validated methods & errors
  580. DLScriptData *data_ptr = script->script_data;
  581. while (data_ptr) {
  582. Map<StringName, DLScriptData::Method>::Element *E = data_ptr->methods.find(p_method);
  583. if (E) {
  584. E->get().method.method((godot_object *)owner, E->get().method.method_data, userdata, p_argcount, (godot_variant **)p_args);
  585. }
  586. data_ptr = data_ptr->base_data;
  587. }
  588. }
  589. void DLInstance::_ml_call_reversed(DLScriptData *data_ptr, const StringName &p_method, const Variant **p_args, int p_argcount) {
  590. // TODO: validated methods & errors
  591. if (data_ptr->base_data)
  592. _ml_call_reversed(data_ptr->base_data, p_method, p_args, p_argcount);
  593. // Variant::CallError ce;
  594. Map<StringName, DLScriptData::Method>::Element *E = data_ptr->methods.find(p_method);
  595. if (E) {
  596. E->get().method.method((godot_object *)owner, E->get().method.method_data, userdata, p_argcount, (godot_variant **)p_args);
  597. }
  598. }
  599. void DLInstance::call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount) {
  600. if (script.ptr() && script->script_data) {
  601. _ml_call_reversed(script->script_data, p_method, p_args, p_argcount);
  602. }
  603. }
  604. void DLInstance::notification(int p_notification) {
  605. Variant value = p_notification;
  606. const Variant *args[1] = { &value };
  607. call_multilevel(DLScriptLanguage::singleton->strings._notification, args, 1);
  608. }
  609. Ref<Script> DLInstance::get_script() const {
  610. return script;
  611. }
  612. ScriptLanguage *DLInstance::get_language() {
  613. return DLScriptLanguage::singleton;
  614. }
  615. ScriptInstance::RPCMode DLInstance::get_rpc_mode(const StringName &p_method) const {
  616. DLScriptData::Method m = script->script_data->methods[p_method];
  617. switch (m.rpc_mode) {
  618. case GODOT_METHOD_RPC_MODE_DISABLED:
  619. return RPC_MODE_DISABLED;
  620. case GODOT_METHOD_RPC_MODE_REMOTE:
  621. return RPC_MODE_REMOTE;
  622. case GODOT_METHOD_RPC_MODE_SYNC:
  623. return RPC_MODE_SYNC;
  624. case GODOT_METHOD_RPC_MODE_MASTER:
  625. return RPC_MODE_MASTER;
  626. case GODOT_METHOD_RPC_MODE_SLAVE:
  627. return RPC_MODE_SLAVE;
  628. default:
  629. return RPC_MODE_DISABLED;
  630. }
  631. }
  632. ScriptInstance::RPCMode DLInstance::get_rset_mode(const StringName &p_variable) const {
  633. DLScriptData::Property p = script->script_data->properties[p_variable];
  634. switch (p.rset_mode) {
  635. case GODOT_METHOD_RPC_MODE_DISABLED:
  636. return RPC_MODE_DISABLED;
  637. case GODOT_METHOD_RPC_MODE_REMOTE:
  638. return RPC_MODE_REMOTE;
  639. case GODOT_METHOD_RPC_MODE_SYNC:
  640. return RPC_MODE_SYNC;
  641. case GODOT_METHOD_RPC_MODE_MASTER:
  642. return RPC_MODE_MASTER;
  643. case GODOT_METHOD_RPC_MODE_SLAVE:
  644. return RPC_MODE_SLAVE;
  645. default:
  646. return RPC_MODE_DISABLED;
  647. }
  648. }
  649. DLInstance::DLInstance() {
  650. owner = NULL;
  651. userdata = NULL;
  652. }
  653. DLInstance::~DLInstance() {
  654. if (script.is_valid()) {
  655. if (owner) {
  656. script->instances.erase(owner);
  657. }
  658. if (!script->script_data)
  659. return;
  660. script->script_data->destroy_func.destroy_func((godot_object *)owner, script->script_data->destroy_func.method_data, userdata);
  661. if (script->script_data->destroy_func.free_func)
  662. script->script_data->destroy_func.free_func(script->script_data->destroy_func.method_data);
  663. if (script->script_data->create_func.free_func)
  664. script->script_data->create_func.free_func(script->script_data->create_func.method_data);
  665. }
  666. }
  667. // Language
  668. DLScriptLanguage *DLScriptLanguage::singleton = NULL;
  669. String DLScriptLanguage::get_name() const {
  670. return "DLScript";
  671. }
  672. bool DLScriptLanguage::is_library_initialized(const String &p_path) {
  673. return initialized_libraries.has(p_path);
  674. }
  675. void DLScriptLanguage::set_library_initialized(const String &p_path, DLLibrary *p_dllibrary) {
  676. initialized_libraries[p_path] = p_dllibrary;
  677. }
  678. DLLibrary *DLScriptLanguage::get_library_dllibrary(const String &p_path) {
  679. return initialized_libraries[p_path];
  680. }
  681. void DLScriptLanguage::set_library_uninitialized(const String &p_path) {
  682. initialized_libraries.erase(p_path);
  683. }
  684. void DLScriptLanguage::init() {
  685. // TODO: Expose globals
  686. GLOBAL_DEF("dlscript/default_dllibrary", "");
  687. PropertyInfo prop_info(Variant::STRING, "dlscript/default_dllibrary", PROPERTY_HINT_FILE, "tres,res,dllib");
  688. GlobalConfig::get_singleton()->set_custom_property_info("dlscript/default_dllibrary", prop_info);
  689. // generate bindings
  690. #if defined(TOOLS_ENABLED) && defined(DEBUG_METHODS_ENABLED)
  691. List<String> args = OS::get_singleton()->get_cmdline_args();
  692. List<String>::Element *E = args.find("--dlscript-generate-json-api");
  693. if (E && E->next()) {
  694. if (generate_c_api(E->next()->get()) != OK) {
  695. ERR_PRINT("Failed to generate C API\n");
  696. }
  697. }
  698. #endif
  699. }
  700. String DLScriptLanguage::get_type() const {
  701. return "DLScript";
  702. }
  703. String DLScriptLanguage::get_extension() const {
  704. return "dl";
  705. }
  706. Error DLScriptLanguage::execute_file(const String &p_path) {
  707. return OK; // ??
  708. }
  709. void DLScriptLanguage::finish() {
  710. // cleanup is for noobs
  711. }
  712. // scons doesn't want to link in the api source so we need to call a dummy function to cause it to link
  713. extern "C" void _api_anchor();
  714. void DLScriptLanguage::_compile_dummy_for_the_api() {
  715. _api_anchor();
  716. }
  717. Ref<Script> DLScriptLanguage::get_template(const String &p_class_name, const String &p_base_class_name) const {
  718. DLScript *src = memnew(DLScript);
  719. src->set_script_name(p_class_name);
  720. return Ref<DLScript>(src);
  721. }
  722. bool DLScriptLanguage::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 {
  723. return false; // TODO
  724. }
  725. Script *DLScriptLanguage::create_script() const {
  726. DLScript *scr = memnew(DLScript);
  727. return scr;
  728. }
  729. bool DLScriptLanguage::has_named_classes() const {
  730. return true;
  731. }
  732. int DLScriptLanguage::find_function(const String &p_function, const String &p_code) const {
  733. return -1; // No source code!
  734. }
  735. String DLScriptLanguage::make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const {
  736. return ""; // No source code!
  737. }
  738. void DLScriptLanguage::add_global_constant(const StringName &p_variable, const Variant &p_value) {
  739. // TODO TODO TODO
  740. }
  741. // TODO: Any debugging? (research)
  742. String DLScriptLanguage::debug_get_error() const {
  743. return "";
  744. }
  745. int DLScriptLanguage::debug_get_stack_level_count() const {
  746. return 1; // ?
  747. }
  748. int DLScriptLanguage::debug_get_stack_level_line(int p_level) const {
  749. return -1;
  750. }
  751. String DLScriptLanguage::debug_get_stack_level_function(int p_level) const {
  752. return "[native code]"; // ?
  753. }
  754. String DLScriptLanguage::debug_get_stack_level_source(int p_level) const {
  755. return "";
  756. }
  757. void DLScriptLanguage::debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {}
  758. void DLScriptLanguage::debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {}
  759. String DLScriptLanguage::debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems, int p_max_depth) {
  760. return ""; // ??
  761. }
  762. void DLScriptLanguage::reload_all_scripts() {
  763. // @Todo
  764. }
  765. void DLScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload) {
  766. // @Todo
  767. OS::get_singleton()->print("reload tool scripts\n");
  768. }
  769. void DLScriptLanguage::get_recognized_extensions(List<String> *p_extensions) const {
  770. p_extensions->push_back("dl"); // Container file format
  771. }
  772. void DLScriptLanguage::get_public_functions(List<MethodInfo> *p_functions) const {
  773. }
  774. void DLScriptLanguage::get_public_constants(List<Pair<String, Variant> > *p_constants) const {
  775. }
  776. // TODO: all profilling
  777. void DLScriptLanguage::profiling_start() {
  778. }
  779. void DLScriptLanguage::profiling_stop() {
  780. }
  781. int DLScriptLanguage::profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max) {
  782. return 0;
  783. }
  784. int DLScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max) {
  785. return 0;
  786. }
  787. void DLScriptLanguage::frame() {
  788. }
  789. String DLScriptLanguage::get_init_symbol_name() {
  790. return "godot_dlscript_init"; // TODO: Maybe make some internal function which would do the actual stuff
  791. }
  792. String DLScriptLanguage::get_terminate_symbol_name() {
  793. return "godot_dlscript_terminate";
  794. }
  795. DLScriptLanguage::DLScriptLanguage() {
  796. ERR_FAIL_COND(singleton);
  797. strings._notification = StringName("_notification");
  798. singleton = this;
  799. initialized_libraries = Map<String, DLLibrary *>();
  800. }
  801. DLScriptLanguage::~DLScriptLanguage() {
  802. singleton = NULL;
  803. }
  804. RES ResourceFormatLoaderDLScript::load(const String &p_path, const String &p_original_path, Error *r_error) {
  805. ResourceFormatLoaderText rsflt;
  806. return rsflt.load(p_path, p_original_path, r_error);
  807. }
  808. void ResourceFormatLoaderDLScript::get_recognized_extensions(List<String> *p_extensions) const {
  809. p_extensions->push_back("dl");
  810. }
  811. bool ResourceFormatLoaderDLScript::handles_type(const String &p_type) const {
  812. return (p_type == "Script" || p_type == "DLScript");
  813. }
  814. String ResourceFormatLoaderDLScript::get_resource_type(const String &p_path) const {
  815. String el = p_path.get_extension().to_lower();
  816. if (el == "dl")
  817. return "DLScript";
  818. return "";
  819. }
  820. Error ResourceFormatSaverDLScript::save(const String &p_path, const RES &p_resource, uint32_t p_flags) {
  821. ResourceFormatSaverText rfst;
  822. return rfst.save(p_path, p_resource, p_flags);
  823. }
  824. bool ResourceFormatSaverDLScript::recognize(const RES &p_resource) const {
  825. return p_resource->cast_to<DLScript>() != NULL;
  826. }
  827. void ResourceFormatSaverDLScript::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const {
  828. if (p_resource->cast_to<DLScript>()) {
  829. p_extensions->push_back("dl");
  830. }
  831. }