script_debugger_remote.cpp 26 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025
  1. /*************************************************************************/
  2. /* script_debugger_remote.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* http://www.godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2016 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 "script_debugger_remote.h"
  30. #include "os/os.h"
  31. #include "io/ip.h"
  32. #include "globals.h"
  33. #include "os/input.h"
  34. void ScriptDebuggerRemote::_send_video_memory() {
  35. List<ResourceUsage> usage;
  36. if (resource_usage_func)
  37. resource_usage_func(&usage);
  38. usage.sort();
  39. packet_peer_stream->put_var("message:video_mem");
  40. packet_peer_stream->put_var(usage.size()*4);
  41. for(List<ResourceUsage>::Element *E=usage.front();E;E=E->next()) {
  42. packet_peer_stream->put_var(E->get().path);
  43. packet_peer_stream->put_var(E->get().type);
  44. packet_peer_stream->put_var(E->get().format);
  45. packet_peer_stream->put_var(E->get().vram);
  46. }
  47. }
  48. Error ScriptDebuggerRemote::connect_to_host(const String& p_host,uint16_t p_port) {
  49. IP_Address ip;
  50. if (p_host.is_valid_ip_address())
  51. ip=p_host;
  52. else
  53. ip = IP::get_singleton()->resolve_hostname(p_host);
  54. int port = p_port;
  55. int tries = 3;
  56. tcp_client->connect(ip, port);
  57. while (tries--) {
  58. if (tcp_client->get_status() == StreamPeerTCP::STATUS_CONNECTED) {
  59. break;
  60. } else {
  61. OS::get_singleton()->delay_usec(1000000);
  62. print_line("Remote Debugger: Connection failed with status: " + String::num(tcp_client->get_status())+"'', retrying in 1 sec.");
  63. };
  64. };
  65. if (tcp_client->get_status() != StreamPeerTCP::STATUS_CONNECTED) {
  66. print_line("Remote Debugger: Unable to connect");
  67. return FAILED;
  68. };
  69. // print_line("Remote Debugger: Connection OK!");
  70. packet_peer_stream->set_stream_peer(tcp_client);
  71. return OK;
  72. }
  73. static int _ScriptDebuggerRemote_found_id=0;
  74. static Object* _ScriptDebuggerRemote_find=NULL;
  75. static void _ScriptDebuggerRemote_debug_func(Object *p_obj) {
  76. if (_ScriptDebuggerRemote_find==p_obj) {
  77. _ScriptDebuggerRemote_found_id=p_obj->get_instance_ID();
  78. }
  79. }
  80. static ObjectID safe_get_instance_id(const Variant& p_v) {
  81. Object *o = p_v;
  82. if (o==NULL)
  83. return 0;
  84. else {
  85. REF r = p_v;
  86. if (r.is_valid()) {
  87. return r->get_instance_ID();
  88. } else {
  89. _ScriptDebuggerRemote_found_id=0;
  90. _ScriptDebuggerRemote_find=NULL;
  91. ObjectDB::debug_objects(_ScriptDebuggerRemote_debug_func);
  92. return _ScriptDebuggerRemote_found_id;
  93. }
  94. }
  95. }
  96. void ScriptDebuggerRemote::debug(ScriptLanguage *p_script,bool p_can_continue) {
  97. //this function is called when there is a debugger break (bug on script)
  98. //or when execution is paused from editor
  99. if (!tcp_client->is_connected()) {
  100. ERR_EXPLAIN("Script Debugger failed to connect, but being used anyway.");
  101. ERR_FAIL();
  102. }
  103. packet_peer_stream->put_var("debug_enter");
  104. packet_peer_stream->put_var(2);
  105. packet_peer_stream->put_var(p_can_continue);
  106. packet_peer_stream->put_var(p_script->debug_get_error());
  107. skip_profile_frame=true; // to avoid super long frame time for the frame
  108. Input::MouseMode mouse_mode=Input::get_singleton()->get_mouse_mode();
  109. if (mouse_mode!=Input::MOUSE_MODE_VISIBLE)
  110. Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE);
  111. while(true) {
  112. _get_output();
  113. if (packet_peer_stream->get_available_packet_count()>0) {
  114. Variant var;
  115. Error err = packet_peer_stream->get_var(var);
  116. ERR_CONTINUE( err != OK);
  117. ERR_CONTINUE( var.get_type()!=Variant::ARRAY );
  118. Array cmd = var;
  119. ERR_CONTINUE( cmd.size()==0);
  120. ERR_CONTINUE( cmd[0].get_type()!=Variant::STRING );
  121. String command = cmd[0];
  122. if (command=="get_stack_dump") {
  123. packet_peer_stream->put_var("stack_dump");
  124. int slc = p_script->debug_get_stack_level_count();
  125. packet_peer_stream->put_var( slc );
  126. for(int i=0;i<slc;i++) {
  127. Dictionary d;
  128. d["file"]=p_script->debug_get_stack_level_source(i);
  129. d["line"]=p_script->debug_get_stack_level_line(i);
  130. d["function"]=p_script->debug_get_stack_level_function(i);
  131. //d["id"]=p_script->debug_get_stack_level_
  132. d["id"]=0;
  133. packet_peer_stream->put_var( d );
  134. }
  135. } else if (command=="get_stack_frame_vars") {
  136. cmd.remove(0);
  137. ERR_CONTINUE( cmd.size()!=1 );
  138. int lv = cmd[0];
  139. List<String> members;
  140. List<Variant> member_vals;
  141. p_script->debug_get_stack_level_members(lv,&members,&member_vals);
  142. ERR_CONTINUE( members.size() !=member_vals.size() );
  143. List<String> locals;
  144. List<Variant> local_vals;
  145. p_script->debug_get_stack_level_locals(lv,&locals,&local_vals);
  146. ERR_CONTINUE( locals.size() !=local_vals.size() );
  147. packet_peer_stream->put_var("stack_frame_vars");
  148. packet_peer_stream->put_var(2+locals.size()*2+members.size()*2);
  149. { //members
  150. packet_peer_stream->put_var(members.size());
  151. List<String>::Element *E=members.front();
  152. List<Variant>::Element *F=member_vals.front();
  153. while(E) {
  154. if (F->get().get_type()==Variant::OBJECT) {
  155. packet_peer_stream->put_var("*"+E->get());
  156. packet_peer_stream->put_var(safe_get_instance_id(F->get()));
  157. } else {
  158. packet_peer_stream->put_var(E->get());
  159. packet_peer_stream->put_var(F->get());
  160. }
  161. E=E->next();
  162. F=F->next();
  163. }
  164. }
  165. { //locals
  166. packet_peer_stream->put_var(locals.size());
  167. List<String>::Element *E=locals.front();
  168. List<Variant>::Element *F=local_vals.front();
  169. while(E) {
  170. if (F->get().get_type()==Variant::OBJECT) {
  171. packet_peer_stream->put_var("*"+E->get());
  172. packet_peer_stream->put_var(safe_get_instance_id(F->get()));
  173. } else {
  174. packet_peer_stream->put_var(E->get());
  175. packet_peer_stream->put_var(F->get());
  176. }
  177. E=E->next();
  178. F=F->next();
  179. }
  180. }
  181. } else if (command=="step") {
  182. set_depth(-1);
  183. set_lines_left(1);
  184. break;
  185. } else if (command=="next") {
  186. set_depth(0);
  187. set_lines_left(1);
  188. break;
  189. } else if (command=="continue") {
  190. set_depth(-1);
  191. set_lines_left(-1);
  192. break;
  193. } else if (command=="break") {
  194. ERR_PRINT("Got break when already broke!");
  195. break;
  196. } else if (command=="request_scene_tree") {
  197. if (request_scene_tree)
  198. request_scene_tree(request_scene_tree_ud);
  199. } else if (command=="request_video_mem") {
  200. _send_video_memory();
  201. } else if (command=="inspect_object") {
  202. ObjectID id = cmd[1];
  203. _send_object_id(id);
  204. } else if (command=="set_object_property") {
  205. _set_object_property(cmd[1],cmd[2],cmd[3]);
  206. } else if (command=="breakpoint") {
  207. bool set = cmd[3];
  208. if (set)
  209. insert_breakpoint(cmd[2],cmd[1]);
  210. else
  211. remove_breakpoint(cmd[2],cmd[1]);
  212. } else {
  213. _parse_live_edit(cmd);
  214. }
  215. } else {
  216. OS::get_singleton()->delay_usec(10000);
  217. }
  218. }
  219. packet_peer_stream->put_var("debug_exit");
  220. packet_peer_stream->put_var(0);
  221. if (mouse_mode!=Input::MOUSE_MODE_VISIBLE)
  222. Input::get_singleton()->set_mouse_mode(mouse_mode);
  223. }
  224. void ScriptDebuggerRemote::_get_output() {
  225. mutex->lock();
  226. if (output_strings.size()) {
  227. locking=true;
  228. packet_peer_stream->put_var("output");
  229. packet_peer_stream->put_var(output_strings .size());
  230. while(output_strings.size()) {
  231. packet_peer_stream->put_var(output_strings.front()->get());
  232. output_strings.pop_front();
  233. }
  234. locking=false;
  235. }
  236. while (messages.size()) {
  237. locking=true;
  238. packet_peer_stream->put_var("message:"+messages.front()->get().message);
  239. packet_peer_stream->put_var(messages.front()->get().data.size());
  240. for(int i=0;i<messages.front()->get().data.size();i++) {
  241. packet_peer_stream->put_var(messages.front()->get().data[i]);
  242. }
  243. messages.pop_front();
  244. locking=false;
  245. }
  246. while (errors.size()) {
  247. locking=true;
  248. packet_peer_stream->put_var("error");
  249. OutputError oe = errors.front()->get();
  250. packet_peer_stream->put_var(oe.callstack.size()+2);
  251. Array error_data;
  252. error_data.push_back(oe.hr);
  253. error_data.push_back(oe.min);
  254. error_data.push_back(oe.sec);
  255. error_data.push_back(oe.msec);
  256. error_data.push_back(oe.source_func);
  257. error_data.push_back(oe.source_file);
  258. error_data.push_back(oe.source_line);
  259. error_data.push_back(oe.error);
  260. error_data.push_back(oe.error_descr);
  261. error_data.push_back(oe.warning);
  262. packet_peer_stream->put_var(error_data);
  263. packet_peer_stream->put_var(oe.callstack.size());
  264. for(int i=0;i<oe.callstack.size();i++) {
  265. packet_peer_stream->put_var(oe.callstack[i]);
  266. }
  267. errors.pop_front();
  268. locking=false;
  269. }
  270. mutex->unlock();
  271. }
  272. void ScriptDebuggerRemote::line_poll() {
  273. //the purpose of this is just processing events every now and then when the script might get too busy
  274. //otherwise bugs like infinite loops cant be catched
  275. if (poll_every%2048==0)
  276. _poll_events();
  277. poll_every++;
  278. }
  279. void ScriptDebuggerRemote::_err_handler(void* ud,const char* p_func,const char*p_file,int p_line,const char *p_err, const char * p_descr,ErrorHandlerType p_type) {
  280. if (p_type==ERR_HANDLER_SCRIPT)
  281. return; //ignore script errors, those go through debugger
  282. ScriptDebuggerRemote *sdr = (ScriptDebuggerRemote*)ud;
  283. OutputError oe;
  284. oe.error=p_err;
  285. oe.error_descr=p_descr;
  286. oe.source_file=p_file;
  287. oe.source_line=p_line;
  288. oe.source_func=p_func;
  289. oe.warning=p_type==ERR_HANDLER_WARNING;
  290. uint64_t time = OS::get_singleton()->get_ticks_msec();
  291. oe.hr=time/3600000;
  292. oe.min=(time/60000)%60;
  293. oe.sec=(time/1000)%60;
  294. oe.msec=time%1000;
  295. Array cstack;
  296. Vector<ScriptLanguage::StackInfo> si;
  297. for(int i=0;i<ScriptServer::get_language_count();i++) {
  298. si=ScriptServer::get_language(i)->debug_get_current_stack_info();
  299. if (si.size())
  300. break;
  301. }
  302. cstack.resize(si.size()*2);
  303. for(int i=0;i<si.size();i++) {
  304. String path;
  305. int line=0;
  306. if (si[i].script.is_valid()) {
  307. path=si[i].script->get_path();
  308. line=si[i].line;
  309. }
  310. cstack[i*2+0]=path;
  311. cstack[i*2+1]=line;
  312. }
  313. oe.callstack=cstack;
  314. sdr->mutex->lock();
  315. if (!sdr->locking && sdr->tcp_client->is_connected()) {
  316. sdr->errors.push_back(oe);
  317. }
  318. sdr->mutex->unlock();
  319. }
  320. bool ScriptDebuggerRemote::_parse_live_edit(const Array& cmd) {
  321. String cmdstr = cmd[0];
  322. if (!live_edit_funcs || !cmdstr.begins_with("live_"))
  323. return false;
  324. //print_line(Variant(cmd).get_construct_string());
  325. if (cmdstr=="live_set_root") {
  326. if (!live_edit_funcs->root_func)
  327. return true;
  328. //print_line("root: "+Variant(cmd).get_construct_string());
  329. live_edit_funcs->root_func(live_edit_funcs->udata,cmd[1],cmd[2]);
  330. } else if (cmdstr=="live_node_path") {
  331. if (!live_edit_funcs->node_path_func)
  332. return true;
  333. //print_line("path: "+Variant(cmd).get_construct_string());
  334. live_edit_funcs->node_path_func(live_edit_funcs->udata,cmd[1],cmd[2]);
  335. } else if (cmdstr=="live_res_path") {
  336. if (!live_edit_funcs->res_path_func)
  337. return true;
  338. live_edit_funcs->res_path_func(live_edit_funcs->udata,cmd[1],cmd[2]);
  339. } else if (cmdstr=="live_node_prop_res") {
  340. if (!live_edit_funcs->node_set_res_func)
  341. return true;
  342. live_edit_funcs->node_set_res_func(live_edit_funcs->udata,cmd[1],cmd[2],cmd[3]);
  343. } else if (cmdstr=="live_node_prop") {
  344. if (!live_edit_funcs->node_set_func)
  345. return true;
  346. live_edit_funcs->node_set_func(live_edit_funcs->udata,cmd[1],cmd[2],cmd[3]);
  347. } else if (cmdstr=="live_res_prop_res") {
  348. if (!live_edit_funcs->res_set_res_func)
  349. return true;
  350. live_edit_funcs->res_set_res_func(live_edit_funcs->udata,cmd[1],cmd[2],cmd[3]);
  351. } else if (cmdstr=="live_res_prop") {
  352. if (!live_edit_funcs->res_set_func)
  353. return true;
  354. live_edit_funcs->res_set_func(live_edit_funcs->udata,cmd[1],cmd[2],cmd[3]);
  355. } else if (cmdstr=="live_node_call") {
  356. if (!live_edit_funcs->node_call_func)
  357. return true;
  358. live_edit_funcs->node_call_func(live_edit_funcs->udata,cmd[1],cmd[2], cmd[3],cmd[4],cmd[5],cmd[6],cmd[7]);
  359. } else if (cmdstr=="live_res_call") {
  360. if (!live_edit_funcs->res_call_func)
  361. return true;
  362. live_edit_funcs->res_call_func(live_edit_funcs->udata,cmd[1],cmd[2], cmd[3],cmd[4],cmd[5],cmd[6],cmd[7]);
  363. } else if (cmdstr=="live_create_node") {
  364. live_edit_funcs->tree_create_node_func(live_edit_funcs->udata,cmd[1],cmd[2],cmd[3]);
  365. } else if (cmdstr=="live_instance_node") {
  366. live_edit_funcs->tree_instance_node_func(live_edit_funcs->udata,cmd[1],cmd[2],cmd[3]);
  367. } else if (cmdstr=="live_remove_node") {
  368. live_edit_funcs->tree_remove_node_func(live_edit_funcs->udata,cmd[1]);
  369. } else if (cmdstr=="live_remove_and_keep_node") {
  370. live_edit_funcs->tree_remove_and_keep_node_func(live_edit_funcs->udata,cmd[1],cmd[2]);
  371. } else if (cmdstr=="live_restore_node") {
  372. live_edit_funcs->tree_restore_node_func(live_edit_funcs->udata,cmd[1],cmd[2],cmd[3]);
  373. } else if (cmdstr=="live_duplicate_node") {
  374. live_edit_funcs->tree_duplicate_node_func(live_edit_funcs->udata,cmd[1],cmd[2]);
  375. } else if (cmdstr=="live_reparent_node") {
  376. live_edit_funcs->tree_reparent_node_func(live_edit_funcs->udata,cmd[1],cmd[2],cmd[3],cmd[4]);
  377. } else {
  378. return false;
  379. }
  380. return true;
  381. }
  382. void ScriptDebuggerRemote::_send_object_id(ObjectID p_id) {
  383. Object* obj = ObjectDB::get_instance(p_id);
  384. if (!obj)
  385. return;
  386. List<PropertyInfo> pinfo;
  387. obj->get_property_list(&pinfo,true);
  388. int props_to_send=0;
  389. for (List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) {
  390. if (E->get().usage&(PROPERTY_USAGE_EDITOR|PROPERTY_USAGE_CATEGORY)) {
  391. props_to_send++;
  392. }
  393. }
  394. packet_peer_stream->put_var("message:inspect_object");
  395. packet_peer_stream->put_var(props_to_send*5+4);
  396. packet_peer_stream->put_var(p_id);
  397. packet_peer_stream->put_var(obj->get_type());
  398. if (obj->is_type("Resource") || obj->is_type("Node"))
  399. packet_peer_stream->put_var(obj->call("get_path"));
  400. else
  401. packet_peer_stream->put_var("");
  402. packet_peer_stream->put_var(props_to_send);
  403. for (List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) {
  404. if (E->get().usage&(PROPERTY_USAGE_EDITOR|PROPERTY_USAGE_CATEGORY)) {
  405. if (E->get().usage&PROPERTY_USAGE_CATEGORY) {
  406. packet_peer_stream->put_var("*"+E->get().name);
  407. } else {
  408. packet_peer_stream->put_var(E->get().name);
  409. }
  410. Variant var = obj->get(E->get().name);
  411. if (E->get().type==Variant::OBJECT || var.get_type()==Variant::OBJECT) {
  412. ObjectID id2;
  413. Object *obj=var;
  414. if (obj) {
  415. id2=obj->get_instance_ID();
  416. } else {
  417. id2=0;
  418. }
  419. packet_peer_stream->put_var(Variant::INT); //hint string
  420. packet_peer_stream->put_var(PROPERTY_HINT_OBJECT_ID); //hint
  421. packet_peer_stream->put_var(E->get().hint_string); //hint string
  422. packet_peer_stream->put_var(id2); //value
  423. } else {
  424. packet_peer_stream->put_var(E->get().type);
  425. packet_peer_stream->put_var(E->get().hint);
  426. packet_peer_stream->put_var(E->get().hint_string);
  427. //only send information that can be sent..
  428. if (var.get_type()==Variant::IMAGE) {
  429. var=Image();
  430. }
  431. if (var.get_type()>=Variant::DICTIONARY) {
  432. var=Array(); //send none for now, may be to big
  433. }
  434. packet_peer_stream->put_var(var);
  435. }
  436. }
  437. }
  438. }
  439. void ScriptDebuggerRemote::_set_object_property(ObjectID p_id, const String& p_property, const Variant& p_value) {
  440. Object* obj = ObjectDB::get_instance(p_id);
  441. if (!obj)
  442. return;
  443. obj->set(p_property,p_value);
  444. }
  445. void ScriptDebuggerRemote::_poll_events() {
  446. //this si called from ::idle_poll, happens only when running the game,
  447. //does not get called while on debug break
  448. while(packet_peer_stream->get_available_packet_count()>0) {
  449. _get_output();
  450. //send over output_strings
  451. Variant var;
  452. Error err = packet_peer_stream->get_var(var);
  453. ERR_CONTINUE( err != OK);
  454. ERR_CONTINUE( var.get_type()!=Variant::ARRAY );
  455. Array cmd = var;
  456. ERR_CONTINUE( cmd.size()==0);
  457. ERR_CONTINUE( cmd[0].get_type()!=Variant::STRING );
  458. String command = cmd[0];
  459. //cmd.remove(0);
  460. if (command=="break") {
  461. if (get_break_language())
  462. debug(get_break_language());
  463. } else if (command=="request_scene_tree") {
  464. if (request_scene_tree)
  465. request_scene_tree(request_scene_tree_ud);
  466. } else if (command=="request_video_mem") {
  467. _send_video_memory();
  468. } else if (command=="inspect_object") {
  469. ObjectID id = cmd[1];
  470. _send_object_id(id);
  471. } else if (command=="set_object_property") {
  472. _set_object_property(cmd[1],cmd[2],cmd[3]);
  473. } else if (command=="start_profiling") {
  474. for(int i=0;i<ScriptServer::get_language_count();i++) {
  475. ScriptServer::get_language(i)->profiling_start();
  476. }
  477. max_frame_functions=cmd[1];
  478. profiler_function_signature_map.clear();
  479. profiling=true;
  480. frame_time=0;
  481. idle_time=0;
  482. fixed_time=0;
  483. fixed_frame_time=0;
  484. print_line("PROFILING ALRIGHT!");
  485. } else if (command=="stop_profiling") {
  486. for(int i=0;i<ScriptServer::get_language_count();i++) {
  487. ScriptServer::get_language(i)->profiling_stop();
  488. }
  489. profiling=false;
  490. _send_profiling_data(false);
  491. print_line("PROFILING END!");
  492. } else if (command=="breakpoint") {
  493. bool set = cmd[3];
  494. if (set)
  495. insert_breakpoint(cmd[2],cmd[1]);
  496. else
  497. remove_breakpoint(cmd[2],cmd[1]);
  498. } else {
  499. _parse_live_edit(cmd);
  500. }
  501. }
  502. }
  503. void ScriptDebuggerRemote::_send_profiling_data(bool p_for_frame) {
  504. int ofs=0;
  505. for(int i=0;i<ScriptServer::get_language_count();i++) {
  506. if (p_for_frame)
  507. ofs+=ScriptServer::get_language(i)->profiling_get_frame_data(&profile_info[ofs],profile_info.size()-ofs);
  508. else
  509. ofs+=ScriptServer::get_language(i)->profiling_get_accumulated_data(&profile_info[ofs],profile_info.size()-ofs);
  510. }
  511. for(int i=0;i<ofs;i++) {
  512. profile_info_ptrs[i]=&profile_info[i];
  513. }
  514. SortArray<ScriptLanguage::ProfilingInfo*,ProfileInfoSort> sa;
  515. sa.sort(profile_info_ptrs.ptr(),ofs);
  516. int to_send=MIN(ofs,max_frame_functions);
  517. //check signatures first
  518. uint64_t total_script_time=0;
  519. for(int i=0;i<to_send;i++) {
  520. if (!profiler_function_signature_map.has(profile_info_ptrs[i]->signature)) {
  521. int idx = profiler_function_signature_map.size();
  522. packet_peer_stream->put_var("profile_sig");
  523. packet_peer_stream->put_var(2);
  524. packet_peer_stream->put_var(profile_info_ptrs[i]->signature);
  525. packet_peer_stream->put_var(idx);
  526. profiler_function_signature_map[profile_info_ptrs[i]->signature]=idx;
  527. }
  528. total_script_time+=profile_info_ptrs[i]->self_time;
  529. }
  530. //send frames then
  531. if (p_for_frame) {
  532. packet_peer_stream->put_var("profile_frame");
  533. packet_peer_stream->put_var(8+profile_frame_data.size()*2+to_send*4);
  534. } else {
  535. packet_peer_stream->put_var("profile_total");
  536. packet_peer_stream->put_var(8+to_send*4);
  537. }
  538. packet_peer_stream->put_var(OS::get_singleton()->get_frames_drawn()); //total frame time
  539. packet_peer_stream->put_var(frame_time); //total frame time
  540. packet_peer_stream->put_var(idle_time); //idle frame time
  541. packet_peer_stream->put_var(fixed_time); //fixed frame time
  542. packet_peer_stream->put_var(fixed_frame_time); //fixed frame time
  543. packet_peer_stream->put_var(USEC_TO_SEC(total_script_time)); //total script execution time
  544. if (p_for_frame) {
  545. packet_peer_stream->put_var(profile_frame_data.size()); //how many profile framedatas to send
  546. packet_peer_stream->put_var(to_send); //how many script functions to send
  547. for (int i=0;i<profile_frame_data.size();i++) {
  548. packet_peer_stream->put_var(profile_frame_data[i].name);
  549. packet_peer_stream->put_var(profile_frame_data[i].data);
  550. }
  551. } else {
  552. packet_peer_stream->put_var(0); //how many script functions to send
  553. packet_peer_stream->put_var(to_send); //how many script functions to send
  554. }
  555. for(int i=0;i<to_send;i++) {
  556. int sig_id=-1;
  557. if (profiler_function_signature_map.has(profile_info_ptrs[i]->signature)) {
  558. sig_id=profiler_function_signature_map[profile_info_ptrs[i]->signature];
  559. }
  560. packet_peer_stream->put_var(sig_id);
  561. packet_peer_stream->put_var(profile_info_ptrs[i]->call_count);
  562. packet_peer_stream->put_var(profile_info_ptrs[i]->total_time/1000000.0);
  563. packet_peer_stream->put_var(profile_info_ptrs[i]->self_time/1000000.0);
  564. }
  565. if (p_for_frame) {
  566. profile_frame_data.clear();
  567. }
  568. }
  569. void ScriptDebuggerRemote::idle_poll() {
  570. // this function is called every frame, except when there is a debugger break (::debug() in this class)
  571. // execution stops and remains in the ::debug function
  572. _get_output();
  573. if (requested_quit) {
  574. packet_peer_stream->put_var("kill_me");
  575. packet_peer_stream->put_var(0);
  576. requested_quit=false;
  577. }
  578. if (performance) {
  579. uint64_t pt = OS::get_singleton()->get_ticks_msec();
  580. if (pt-last_perf_time > 1000) {
  581. last_perf_time=pt;
  582. int max = performance->get("MONITOR_MAX");
  583. Array arr;
  584. arr.resize(max);
  585. for(int i=0;i<max;i++) {
  586. arr[i]=performance->call("get_monitor",i);
  587. }
  588. packet_peer_stream->put_var("performance");
  589. packet_peer_stream->put_var(1);
  590. packet_peer_stream->put_var(arr);
  591. }
  592. }
  593. if (profiling) {
  594. if (skip_profile_frame) {
  595. skip_profile_frame=false;
  596. } else {
  597. //send profiling info normally
  598. _send_profiling_data(true);
  599. }
  600. }
  601. _poll_events();
  602. }
  603. void ScriptDebuggerRemote::send_message(const String& p_message, const Array &p_args) {
  604. mutex->lock();
  605. if (!locking && tcp_client->is_connected()) {
  606. Message msg;
  607. msg.message=p_message;
  608. msg.data=p_args;
  609. messages.push_back(msg);
  610. }
  611. mutex->unlock();
  612. }
  613. void ScriptDebuggerRemote::_print_handler(void *p_this,const String& p_string) {
  614. ScriptDebuggerRemote *sdr = (ScriptDebuggerRemote*)p_this;
  615. uint64_t ticks = OS::get_singleton()->get_ticks_usec()/1000;
  616. sdr->msec_count+=ticks-sdr->last_msec;
  617. sdr->last_msec=ticks;
  618. if (sdr->msec_count>1000) {
  619. sdr->char_count=0;
  620. sdr->msec_count=0;
  621. }
  622. String s = p_string;
  623. int allowed_chars = MIN(MAX(sdr->max_cps - sdr->char_count,0), s.length());
  624. if (allowed_chars==0)
  625. return;
  626. if (allowed_chars<s.length()) {
  627. s=s.substr(0,allowed_chars);
  628. }
  629. sdr->char_count+=allowed_chars;
  630. if (sdr->char_count>=sdr->max_cps) {
  631. s+="\n[output overflow, print less text!]\n";
  632. }
  633. sdr->mutex->lock();
  634. if (!sdr->locking && sdr->tcp_client->is_connected()) {
  635. sdr->output_strings.push_back(s);
  636. }
  637. sdr->mutex->unlock();
  638. }
  639. void ScriptDebuggerRemote::request_quit() {
  640. requested_quit=true;
  641. }
  642. void ScriptDebuggerRemote::set_request_scene_tree_message_func(RequestSceneTreeMessageFunc p_func, void *p_udata) {
  643. request_scene_tree=p_func;
  644. request_scene_tree_ud=p_udata;
  645. }
  646. void ScriptDebuggerRemote::set_live_edit_funcs(LiveEditFuncs *p_funcs) {
  647. live_edit_funcs=p_funcs;
  648. }
  649. bool ScriptDebuggerRemote::is_profiling() const {
  650. return profiling;
  651. }
  652. void ScriptDebuggerRemote::add_profiling_frame_data(const StringName& p_name,const Array& p_data){
  653. int idx=-1;
  654. for(int i=0;i<profile_frame_data.size();i++) {
  655. if (profile_frame_data[i].name==p_name) {
  656. idx=i;
  657. break;
  658. }
  659. }
  660. FrameData fd;
  661. fd.name=p_name;
  662. fd.data=p_data;
  663. if (idx==-1) {
  664. profile_frame_data.push_back(fd);
  665. } else {
  666. profile_frame_data[idx]=fd;
  667. }
  668. }
  669. void ScriptDebuggerRemote::profiling_start() {
  670. //ignores this, uses it via connnection
  671. }
  672. void ScriptDebuggerRemote::profiling_end() {
  673. //ignores this, uses it via connnection
  674. }
  675. void ScriptDebuggerRemote::profiling_set_frame_times(float p_frame_time, float p_idle_time, float p_fixed_time, float p_fixed_frame_time) {
  676. frame_time=p_frame_time;
  677. idle_time=p_idle_time;
  678. fixed_time=p_fixed_time;
  679. fixed_frame_time=p_fixed_frame_time;
  680. }
  681. ScriptDebuggerRemote::ResourceUsageFunc ScriptDebuggerRemote::resource_usage_func=NULL;
  682. ScriptDebuggerRemote::ScriptDebuggerRemote() {
  683. tcp_client = StreamPeerTCP::create_ref();
  684. packet_peer_stream = Ref<PacketPeerStream>( memnew(PacketPeerStream) );
  685. packet_peer_stream->set_stream_peer(tcp_client);
  686. mutex = Mutex::create();
  687. locking=false;
  688. phl.printfunc=_print_handler;
  689. phl.userdata=this;
  690. add_print_handler(&phl);
  691. requested_quit=false;
  692. performance = Globals::get_singleton()->get_singleton_object("Performance");
  693. last_perf_time=0;
  694. poll_every=0;
  695. request_scene_tree=NULL;
  696. live_edit_funcs=NULL;
  697. max_cps = GLOBAL_DEF("debug/max_remote_stdout_chars_per_second",2048);
  698. char_count=0;
  699. msec_count=0;
  700. last_msec=0;
  701. skip_profile_frame=false;
  702. eh.errfunc=_err_handler;
  703. eh.userdata=this;
  704. add_error_handler(&eh);
  705. profile_info.resize(CLAMP(int(Globals::get_singleton()->get("debug/profiler_max_functions")),128,65535));
  706. profile_info_ptrs.resize(profile_info.size());
  707. profiling=false;
  708. max_frame_functions=16;
  709. }
  710. ScriptDebuggerRemote::~ScriptDebuggerRemote() {
  711. remove_print_handler(&phl);
  712. remove_error_handler(&eh);
  713. memdelete(mutex);
  714. }