PageRenderTime 56ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/src/mod/commandev.cpp

https://gitlab.com/terencode/remod-racing
C++ | 549 lines | 425 code | 68 blank | 56 comment | 47 complexity | 1ef503ed197cd9cbfd0b779aafccb4a1 MD5 | raw file
  1. /*
  2. * remod: commandev.cpp
  3. * date: 2007
  4. * author: degrave, stormchild
  5. *
  6. * events and events handlers
  7. */
  8. #include "commandev.h"
  9. #include "commandhandler.h"
  10. #include "remod.h"
  11. extern char *strreplace(const char *s, const char *oldval, const char *newval);
  12. namespace remod
  13. {
  14. evt_param::evt_param()
  15. {
  16. type = 0;
  17. value = NULL;
  18. }
  19. evt_param::~evt_param()
  20. {
  21. if(value)
  22. {
  23. switch(type)
  24. {
  25. case 'i':
  26. delete value_i;
  27. break;
  28. case 's':
  29. DELETEA(value_s);
  30. break;
  31. case 'f':
  32. case 'd':
  33. delete value_d;
  34. break;
  35. default:
  36. break;
  37. }
  38. }
  39. }
  40. event::event()
  41. {
  42. custom = NULL;
  43. fmt = NULL;
  44. }
  45. event::~event()
  46. {
  47. DELETEA(custom);
  48. DELETEA(fmt);
  49. evt_param *param;
  50. while(params.length())
  51. {
  52. param = params.remove(0);
  53. delete param;
  54. }
  55. }
  56. vector<event *> events; // events queue
  57. vector<evt_handler> handlers[NUMEVENTS]; //Event handlers
  58. // Conver event name to string
  59. char *event2str(eventType type)
  60. {
  61. if((type >= 0) && (type < NUMEVENTS))
  62. return newstring(eventNames[type]);
  63. else
  64. return newstring("");
  65. }
  66. eventType str2event(const char *name)
  67. {
  68. loopi(NUMEVENTS)
  69. if(strcmp(name, eventNames[i]) == 0) return (eventType)i;
  70. return CUSTOMEVENT;
  71. }
  72. event* storeevent(eventType etype, const char *custom, const char *fmt, va_list vl)
  73. {
  74. event *e = new event;
  75. e->evt_type = etype;
  76. if(etype == CUSTOMEVENT)
  77. {
  78. if(custom && custom[0])
  79. e->custom = newstring(custom);
  80. else
  81. // costom event not defined
  82. return NULL;
  83. }
  84. e->fmt = newstring(fmt);
  85. // store params
  86. if(fmt && fmt[0])
  87. {
  88. const char *c = fmt;
  89. while(*c)
  90. {
  91. evt_param *param = new evt_param;
  92. param->type = *c;
  93. switch(*c++)
  94. {
  95. case 'i':
  96. {
  97. param->value_i = new int;
  98. *param->value_i = va_arg(vl, int);
  99. break;
  100. }
  101. case 's':
  102. {
  103. char *s = va_arg(vl, char*);
  104. param->value_s = newstring(s ? s : "");
  105. break;
  106. }
  107. case 'f':
  108. case 'd':
  109. {
  110. param->value_d = new double;
  111. *param->value_d = va_arg(vl, double);
  112. break;
  113. }
  114. default:
  115. {
  116. conoutf("unknown format parameter \"%c\"", *c);
  117. va_arg(vl, int);
  118. break;
  119. }
  120. }
  121. e->params.add(param);
  122. }
  123. }
  124. return e;
  125. }
  126. // debug information
  127. void listparams(vector<evt_param *> &params)
  128. {
  129. evt_param *param;
  130. loopv(params)
  131. {
  132. param = params[i];
  133. printf("arg%i(%c)=", i, param->type);
  134. switch(param->type)
  135. {
  136. case 'i': conoutf("%i", *param->value_i); break;
  137. case 'f':
  138. case 'd': conoutf("%f", *param->value_d); break;
  139. case 's': conoutf("%s", param->value_s); break;
  140. default: conoutf("unknown");
  141. }
  142. }
  143. }
  144. void eventinfo(event *ev)
  145. {
  146. conoutf("eventinfo:");
  147. conoutf("\tevent type: %s", event2str(ev->evt_type));
  148. conoutf("\tparams(%i)", ev->params.length());
  149. listparams(ev->params);
  150. }
  151. template <typename T>
  152. T *getarg(vector<evt_param *> &params)
  153. {
  154. if(params.length())
  155. {
  156. T *value = new T; // int *value = new int;
  157. T *tmp;
  158. evt_param *param = params.remove(0);
  159. tmp = (T*)param->value;
  160. *value = *tmp;
  161. delete param;
  162. return value;
  163. }
  164. return NULL;
  165. }
  166. // Spezialization for char*
  167. template <>
  168. char *getarg<char>(vector<evt_param *> &params)
  169. {
  170. if(params.length())
  171. {
  172. evt_param *param = params.remove(0);
  173. char *value = newstring(param->value_s);
  174. delete param;
  175. return value;
  176. }
  177. return NULL;
  178. }
  179. void addevent(eventType etype, const char *custom, const char *fmt, va_list vl)
  180. {
  181. event *e;
  182. if((e = storeevent(etype, NULL, fmt, vl)))
  183. events.add(e);
  184. }
  185. void addevent(event *e)
  186. {
  187. events.add(e);
  188. }
  189. //Add script callback to event
  190. void addhandler(const char *evt_type, const char *callbackcmd)
  191. {
  192. if(evt_type && evt_type[0] && callbackcmd && callbackcmd[0])
  193. {
  194. eventType etype = str2event(evt_type);
  195. evt_handler eh;
  196. eh.evt_type = etype;
  197. loopv(handlers[etype])
  198. {
  199. evt_handler &checkeh = handlers[etype][i];
  200. if (!strcmp(callbackcmd, checkeh.evt_cmd))
  201. {
  202. return; // this command is already linked to this handler
  203. }
  204. }
  205. if(etype == CUSTOMEVENT) eh.custom = newstring(evt_type);
  206. eh.evt_cmd = newstring(callbackcmd);
  207. handlers[etype].add(eh);
  208. }
  209. }
  210. void delhandler(const char* evt_type, const char *cmd)
  211. {
  212. eventType etype = str2event(evt_type);
  213. loopv(handlers[etype])
  214. {
  215. evt_handler &eh = handlers[etype][i];
  216. if(strcmp(cmd, eh.evt_cmd) == 0)
  217. {
  218. DELETEA(eh.evt_cmd);
  219. if(etype == CUSTOMEVENT) DELETEA(eh.custom);
  220. handlers[etype].remove(i);
  221. }
  222. }
  223. }
  224. bool ishandle(eventType etype)
  225. {
  226. return handlers[etype].length();
  227. }
  228. #if 1
  229. //Debug
  230. void dumphandlers()
  231. {
  232. loopi(NUMEVENTS)
  233. if(handlers[i].length())
  234. loopvj(handlers[i])
  235. {
  236. evt_handler &eh = handlers[i][j];
  237. conoutf("Handler %s = %s\n", event2str((eventType)eh.evt_type), eh.evt_cmd);
  238. }
  239. }
  240. /**
  241. * Print all event handlers (debug mode only)
  242. * @group event
  243. * @example dumphandlers
  244. */
  245. COMMAND(dumphandlers, "");
  246. #endif
  247. void clearhandlers()
  248. {
  249. loopi(NUMEVENTS)
  250. handlers[i].shrink(0);
  251. }
  252. void triggerEvent(event *ev)
  253. {
  254. if(!ev) return;
  255. eventType etype = ev->evt_type;
  256. switch(etype)
  257. {
  258. case ONCOMMAND:
  259. {
  260. int *cn = getarg<int>(ev->params);
  261. const char *command_str = getarg<char>(ev->params);
  262. //splitting command_string to command_name and command_params
  263. char *command_name;
  264. char *command_params;
  265. const char *spacepos = strstr(command_str, " ");
  266. if(!spacepos)
  267. {
  268. command_name = newstring(command_str);
  269. command_params = newstring("");
  270. }
  271. else
  272. {
  273. command_params = newstring(spacepos+1);
  274. command_name = newstring(command_str, (size_t) (spacepos - command_str));
  275. }
  276. // execute command
  277. remod::oncommand(*cn, command_name, command_params);
  278. delete(cn);
  279. DELETEA(command_str);
  280. DELETEA(command_name);
  281. DELETEA(command_params);
  282. return;
  283. }
  284. #ifdef IRC
  285. case IRC_ONCOMMAND:
  286. {
  287. //getting username
  288. const char *user = getarg<char>(ev->params);
  289. const char *command_str = getarg<char>(ev->params);
  290. //splitting command_string to command_name and command_params
  291. char *command_name;
  292. char *command_params;
  293. const char *spacepos = strstr(command_str, " ");
  294. if(!spacepos)
  295. {
  296. command_name = newstring(command_str);
  297. command_params = newstring("");
  298. }
  299. else
  300. {
  301. command_params = newstring(spacepos+1);
  302. command_name = newstring(command_str, (size_t) (spacepos - command_str));
  303. }
  304. // execute irc command
  305. remod::irc_oncommand(user, command_name, command_params);
  306. DELETEA(user);
  307. DELETEA(command_str);
  308. DELETEA(command_name);
  309. DELETEA(command_params);
  310. return;
  311. }
  312. #endif
  313. default:
  314. {
  315. if(ishandle(etype))
  316. {
  317. char *evparams = newstring("");
  318. //Check params
  319. if(ev->fmt && ev->fmt[0])
  320. {
  321. //Convert params to string
  322. const char *c = ev->fmt;
  323. while(*c)
  324. {
  325. const char* p = NULL;
  326. switch(*c++)
  327. {
  328. case 'i':
  329. {
  330. int *i = getarg<int>(ev->params);
  331. concatpstring(&evparams, 2, " ", intstr(*i));
  332. delete i;
  333. break;
  334. }
  335. case 's':
  336. {
  337. p = getarg<char>(ev->params);
  338. if(p)
  339. concatpstring(&evparams, 2, " ", escapestring(p));
  340. else
  341. concatpstring(&evparams, "\"\"");
  342. DELETEA(p);
  343. break;
  344. }
  345. case 'f':
  346. case 'd':
  347. {
  348. double *d = getarg<double>(ev->params);
  349. concatpstring(&evparams, 2, " ", floatstr(*d));
  350. delete d;
  351. break;
  352. }
  353. default:
  354. {
  355. //Read and forgot
  356. int *i = getarg<int>(ev->params);
  357. delete i;
  358. break;
  359. }
  360. }
  361. }
  362. }
  363. //Process handlers
  364. if(etype != CUSTOMEVENT) // standart event
  365. {
  366. loopv(handlers[etype])
  367. {
  368. evt_handler &eh = handlers[etype][i];
  369. char *evcmd = newstring(eh.evt_cmd);
  370. concatpstring(&evcmd, evparams);
  371. execute(evcmd);
  372. DELETEA(evcmd);
  373. }
  374. }
  375. else if(ev->custom && ev->custom[0]) // custom user script triggered event
  376. {
  377. loopv(handlers[etype])
  378. {
  379. evt_handler &eh = handlers[etype][i];
  380. if(strcmp(ev->custom, eh.custom) == 0)
  381. {
  382. char *evcmd = newstring(eh.evt_cmd);
  383. concatpstring(&evcmd, evparams);
  384. execute(evcmd);
  385. DELETEA(evcmd);
  386. }
  387. }
  388. }
  389. DELETEA(evparams);
  390. }
  391. }
  392. }
  393. }
  394. // add event to queue
  395. void onevent(eventType etype, const char *fmt, ...)
  396. {
  397. if((etype < 0) || (etype >= NUMEVENTS)) return;
  398. va_list vl;
  399. va_start(vl, fmt);
  400. addevent(etype, NULL, fmt, vl);
  401. va_end(vl);
  402. }
  403. // execute event instantly
  404. void oneventi(eventType etype, const char *fmt, ...)
  405. {
  406. if((etype < 0) || (etype >= NUMEVENTS)) return;
  407. va_list vl;
  408. va_start(vl, fmt);
  409. event *e = storeevent(etype, NULL, fmt, vl);
  410. triggerEvent(e);
  411. delete e;
  412. va_end(vl);
  413. }
  414. void customEvent(tagval *v, int numargs)
  415. {
  416. if(!numargs) return;
  417. event *e = new event;
  418. const char *custom = v[0].getstr(); // custom event name
  419. e->evt_type = CUSTOMEVENT;
  420. e->custom = newstring(custom);
  421. // event have args
  422. if(numargs>1)
  423. {
  424. vector<char> fmt;
  425. int argnum = 1;
  426. while(argnum < numargs)
  427. {
  428. evt_param *param = new evt_param;
  429. param->type = 's';
  430. param->value_s = newstring(v[argnum].getstr());
  431. e->params.add(param);
  432. fmt.add('s');
  433. argnum++;
  434. }
  435. e->fmt = newstring(fmt.getbuf());
  436. }
  437. addevent(e);
  438. }
  439. void eventsupdate()
  440. {
  441. event *e;
  442. if(events.length())
  443. {
  444. while(events.length())
  445. {
  446. e = events.remove(0);
  447. triggerEvent(e);
  448. delete e;
  449. }
  450. }
  451. }
  452. /**
  453. * Add server event handler to specified event
  454. * @group event
  455. * @arg1 event name
  456. * @arg2 callback function
  457. * @example addhandler "onconnect" log_onconnect
  458. */
  459. COMMAND(addhandler, "ss");
  460. /**
  461. * Add server event handler to specified event. Parameters to callback function depend of event
  462. * @group event
  463. * @arg1 event name
  464. * @arg2 callback function
  465. * @example delhandler "onconnect" log_onconnect
  466. */
  467. COMMAND(delhandler, "ss");
  468. /**
  469. * Clear all server events handlers
  470. * @group event
  471. */
  472. COMMAND(clearhandlers, "");
  473. /**
  474. * Trigger custom event
  475. * @group event
  476. * @arg1 event name
  477. * @arg2 .. argN arguments
  478. * @example event "onsomething" $cn $msg $ratio
  479. */
  480. COMMANDN(event, customEvent, "V");
  481. }