multi_script.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. /*************************************************************************/
  2. /* multi_script.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* http://www.godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2014 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 "multi_script.h"
  30. bool MultiScriptInstance::set(const StringName& p_name, const Variant& p_value) {
  31. ScriptInstance **sarr = instances.ptr();
  32. int sc = instances.size();
  33. for(int i=0;i<sc;i++) {
  34. if (!sarr[i])
  35. continue;
  36. bool found = sarr[i]->set(p_name,p_value);
  37. if (found)
  38. return true;
  39. }
  40. if (String(p_name).begins_with("script_")) {
  41. bool valid;
  42. owner->set(p_name,p_value,&valid);
  43. return valid;
  44. }
  45. return false;
  46. }
  47. bool MultiScriptInstance::get(const StringName& p_name, Variant &r_ret) const{
  48. ScriptInstance **sarr = instances.ptr();
  49. int sc = instances.size();
  50. for(int i=0;i<sc;i++) {
  51. if (!sarr[i])
  52. continue;
  53. bool found = sarr[i]->get(p_name,r_ret);
  54. if (found)
  55. return true;
  56. }
  57. if (String(p_name).begins_with("script_")) {
  58. bool valid;
  59. r_ret=owner->get(p_name,&valid);
  60. return valid;
  61. }
  62. return false;
  63. }
  64. void MultiScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const{
  65. ScriptInstance **sarr = instances.ptr();
  66. int sc = instances.size();
  67. Set<String> existing;
  68. for(int i=0;i<sc;i++) {
  69. if (!sarr[i])
  70. continue;
  71. List<PropertyInfo> pl;
  72. sarr[i]->get_property_list(&pl);
  73. for(List<PropertyInfo>::Element *E=pl.front();E;E=E->next()) {
  74. if (existing.has(E->get().name))
  75. continue;
  76. p_properties->push_back(E->get());
  77. existing.insert(E->get().name);
  78. }
  79. }
  80. p_properties->push_back( PropertyInfo(Variant::NIL,"Scripts",PROPERTY_HINT_NONE,String(),PROPERTY_USAGE_CATEGORY) );
  81. for(int i=0;i<owner->scripts.size();i++) {
  82. p_properties->push_back( PropertyInfo(Variant::OBJECT,"script_"+String::chr('a'+i),PROPERTY_HINT_RESOURCE_TYPE,"Script",PROPERTY_USAGE_EDITOR) );
  83. }
  84. if (owner->scripts.size()<25) {
  85. p_properties->push_back( PropertyInfo(Variant::OBJECT,"script_"+String::chr('a'+(owner->scripts.size())),PROPERTY_HINT_RESOURCE_TYPE,"Script",PROPERTY_USAGE_EDITOR) );
  86. }
  87. }
  88. void MultiScriptInstance::get_method_list(List<MethodInfo> *p_list) const{
  89. ScriptInstance **sarr = instances.ptr();
  90. int sc = instances.size();
  91. Set<StringName> existing;
  92. for(int i=0;i<sc;i++) {
  93. if (!sarr[i])
  94. continue;
  95. List<MethodInfo> ml;
  96. sarr[i]->get_method_list(&ml);
  97. for(List<MethodInfo>::Element *E=ml.front();E;E=E->next()) {
  98. if (existing.has(E->get().name))
  99. continue;
  100. p_list->push_back(E->get());
  101. existing.insert(E->get().name);
  102. }
  103. }
  104. }
  105. bool MultiScriptInstance::has_method(const StringName& p_method) const{
  106. ScriptInstance **sarr = instances.ptr();
  107. int sc = instances.size();
  108. for(int i=0;i<sc;i++) {
  109. if (!sarr[i])
  110. continue;
  111. if (sarr[i]->has_method(p_method))
  112. return true;
  113. }
  114. return false;
  115. }
  116. Variant MultiScriptInstance::call(const StringName& p_method,const Variant** p_args,int p_argcount,Variant::CallError &r_error) {
  117. ScriptInstance **sarr = instances.ptr();
  118. int sc = instances.size();
  119. for(int i=0;i<sc;i++) {
  120. if (!sarr[i])
  121. continue;
  122. Variant r = sarr[i]->call(p_method,p_args,p_argcount,r_error);
  123. if (r_error.error==Variant::CallError::CALL_OK)
  124. return r;
  125. else if (r_error.error!=Variant::CallError::CALL_ERROR_INVALID_METHOD)
  126. return r;
  127. }
  128. r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
  129. return Variant();
  130. }
  131. void MultiScriptInstance::call_multilevel(const StringName& p_method,const Variant** p_args,int p_argcount){
  132. ScriptInstance **sarr = instances.ptr();
  133. int sc = instances.size();
  134. for(int i=0;i<sc;i++) {
  135. if (!sarr[i])
  136. continue;
  137. sarr[i]->call_multilevel(p_method,p_args,p_argcount);
  138. }
  139. }
  140. void MultiScriptInstance::notification(int p_notification){
  141. ScriptInstance **sarr = instances.ptr();
  142. int sc = instances.size();
  143. for(int i=0;i<sc;i++) {
  144. if (!sarr[i])
  145. continue;
  146. sarr[i]->notification(p_notification);
  147. }
  148. }
  149. Ref<Script> MultiScriptInstance::get_script() const {
  150. return owner;
  151. }
  152. ScriptLanguage *MultiScriptInstance::get_language() {
  153. return MultiScriptLanguage::get_singleton();
  154. }
  155. MultiScriptInstance::~MultiScriptInstance() {
  156. owner->remove_instance(object);
  157. }
  158. ///////////////////
  159. bool MultiScript::is_tool() const {
  160. for(int i=0;i<scripts.size();i++) {
  161. if (scripts[i]->is_tool())
  162. return true;
  163. }
  164. return false;
  165. }
  166. bool MultiScript::_set(const StringName& p_name, const Variant& p_value) {
  167. _THREAD_SAFE_METHOD_
  168. String s = String(p_name);
  169. if (s.begins_with("script_")) {
  170. int idx = s[7];
  171. if (idx==0)
  172. return false;
  173. idx-='a';
  174. ERR_FAIL_COND_V(idx<0,false);
  175. Ref<Script> s = p_value;
  176. if (idx<scripts.size()) {
  177. if (s.is_null())
  178. remove_script(idx);
  179. else
  180. set_script(idx,s);
  181. } else if (idx==scripts.size()) {
  182. if (s.is_null())
  183. return false;
  184. add_script(s);
  185. } else
  186. return false;
  187. return true;
  188. }
  189. return false;
  190. }
  191. bool MultiScript::_get(const StringName& p_name,Variant &r_ret) const{
  192. _THREAD_SAFE_METHOD_
  193. String s = String(p_name);
  194. if (s.begins_with("script_")) {
  195. int idx = s[7];
  196. if (idx==0)
  197. return false;
  198. idx-='a';
  199. ERR_FAIL_COND_V(idx<0,false);
  200. if (idx<scripts.size()) {
  201. r_ret=get_script(idx);
  202. return true;
  203. } else if (idx==scripts.size()) {
  204. r_ret=Ref<Script>();
  205. return true;
  206. }
  207. }
  208. return false;
  209. }
  210. void MultiScript::_get_property_list( List<PropertyInfo> *p_list) const{
  211. _THREAD_SAFE_METHOD_
  212. for(int i=0;i<scripts.size();i++) {
  213. p_list->push_back( PropertyInfo(Variant::OBJECT,"script_"+String::chr('a'+i),PROPERTY_HINT_RESOURCE_TYPE,"Script") );
  214. }
  215. if (scripts.size()<25) {
  216. p_list->push_back( PropertyInfo(Variant::OBJECT,"script_"+String::chr('a'+(scripts.size())),PROPERTY_HINT_RESOURCE_TYPE,"Script") );
  217. }
  218. }
  219. void MultiScript::set_script(int p_idx,const Ref<Script>& p_script ) {
  220. _THREAD_SAFE_METHOD_
  221. ERR_FAIL_INDEX(p_idx,scripts.size());
  222. ERR_FAIL_COND( p_script.is_null() );
  223. scripts[p_idx]=p_script;
  224. Ref<Script> s=p_script;
  225. for (Map<Object*,MultiScriptInstance*>::Element *E=instances.front();E;E=E->next()) {
  226. MultiScriptInstance*msi=E->get();
  227. ScriptInstance *si = msi->instances[p_idx];
  228. if (si) {
  229. msi->instances[p_idx]=NULL;
  230. memdelete(si);
  231. }
  232. if (p_script->can_instance())
  233. msi->instances[p_idx]=s->instance_create(msi->object);
  234. }
  235. }
  236. Ref<Script> MultiScript::get_script(int p_idx) const{
  237. _THREAD_SAFE_METHOD_
  238. ERR_FAIL_INDEX_V(p_idx,scripts.size(),Ref<Script>());
  239. return scripts[p_idx];
  240. }
  241. void MultiScript::add_script(const Ref<Script>& p_script){
  242. _THREAD_SAFE_METHOD_
  243. ERR_FAIL_COND( p_script.is_null() );
  244. scripts.push_back(p_script);
  245. Ref<Script> s=p_script;
  246. for (Map<Object*,MultiScriptInstance*>::Element *E=instances.front();E;E=E->next()) {
  247. MultiScriptInstance*msi=E->get();
  248. if (p_script->can_instance())
  249. msi->instances.push_back( s->instance_create(msi->object) );
  250. else
  251. msi->instances.push_back(NULL);
  252. msi->object->_change_notify();
  253. }
  254. _change_notify();
  255. }
  256. void MultiScript::remove_script(int p_idx) {
  257. _THREAD_SAFE_METHOD_
  258. ERR_FAIL_INDEX(p_idx,scripts.size());
  259. scripts.remove(p_idx);
  260. for (Map<Object*,MultiScriptInstance*>::Element *E=instances.front();E;E=E->next()) {
  261. MultiScriptInstance*msi=E->get();
  262. ScriptInstance *si = msi->instances[p_idx];
  263. msi->instances.remove(p_idx);
  264. if (si) {
  265. memdelete(si);
  266. }
  267. msi->object->_change_notify();
  268. }
  269. }
  270. void MultiScript::remove_instance(Object *p_object) {
  271. _THREAD_SAFE_METHOD_
  272. instances.erase(p_object);
  273. }
  274. bool MultiScript::can_instance() const {
  275. return true;
  276. }
  277. StringName MultiScript::get_instance_base_type() const {
  278. return StringName();
  279. }
  280. ScriptInstance* MultiScript::instance_create(Object *p_this) {
  281. _THREAD_SAFE_METHOD_
  282. MultiScriptInstance *msi = memnew( MultiScriptInstance );
  283. msi->object=p_this;
  284. msi->owner=this;
  285. for(int i=0;i<scripts.size();i++) {
  286. ScriptInstance *si;
  287. if (scripts[i]->can_instance())
  288. si = scripts[i]->instance_create(p_this);
  289. else
  290. si=NULL;
  291. msi->instances.push_back(si);
  292. }
  293. instances[p_this]=msi;
  294. p_this->_change_notify();
  295. return msi;
  296. }
  297. bool MultiScript::instance_has(const Object *p_this) const {
  298. _THREAD_SAFE_METHOD_
  299. return instances.has((Object*)p_this);
  300. }
  301. bool MultiScript::has_source_code() const {
  302. return false;
  303. }
  304. String MultiScript::get_source_code() const {
  305. return "";
  306. }
  307. void MultiScript::set_source_code(const String& p_code) {
  308. }
  309. Error MultiScript::reload() {
  310. for(int i=0;i<scripts.size();i++)
  311. scripts[i]->reload();
  312. return OK;
  313. }
  314. String MultiScript::get_node_type() const {
  315. return "";
  316. }
  317. void MultiScript::_bind_methods() {
  318. }
  319. ScriptLanguage *MultiScript::get_language() const {
  320. return MultiScriptLanguage::get_singleton();
  321. }
  322. ///////////////
  323. MultiScript::MultiScript() {
  324. }
  325. MultiScriptLanguage *MultiScriptLanguage::singleton=NULL;