prototype.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. //*****************************************************************************
  2. //
  3. // prototype.c
  4. //
  5. // generic prototype datastructure for anything that can be generated with a
  6. // python script (e.g. object, room, character). Supports inheritance from
  7. // other prototypes.
  8. //
  9. //*****************************************************************************
  10. #include "mud.h"
  11. #include "utils.h"
  12. #include "prototype.h"
  13. #include "storage.h"
  14. #include "room.h"
  15. #include "character.h"
  16. #include "object.h"
  17. #include "world.h"
  18. #include "zone.h"
  19. #include "handler.h"
  20. //*****************************************************************************
  21. // mandatory modules
  22. //*****************************************************************************
  23. #include "scripts/scripts.h"
  24. #include "scripts/pyplugs.h"
  25. #include "scripts/pychar.h"
  26. #include "scripts/pyroom.h"
  27. #include "scripts/pyobj.h"
  28. //*****************************************************************************
  29. // local datastructures, functions, and variables
  30. //*****************************************************************************
  31. struct prototype_data {
  32. char *key;
  33. char *parents;
  34. bool abstract;
  35. BUFFER *script;
  36. PyObject *code;
  37. };
  38. //*****************************************************************************
  39. // implementation of prototype.h
  40. //*****************************************************************************
  41. PROTO_DATA *newProto(void) {
  42. PROTO_DATA *data = malloc(sizeof(PROTO_DATA));
  43. data->key = strdup("");
  44. data->parents = strdup("");
  45. data->abstract = TRUE;
  46. data->script = newBuffer(1);
  47. data->code = NULL;
  48. return data;
  49. }
  50. void deleteProto(PROTO_DATA *data) {
  51. if(data->key) free(data->key);
  52. if(data->parents) free(data->parents);
  53. if(data->script) deleteBuffer(data->script);
  54. Py_XDECREF(data->code);
  55. free(data);
  56. }
  57. void protoCopyTo(PROTO_DATA *from, PROTO_DATA *to) {
  58. protoSetKey(to, protoGetKey(from));
  59. protoSetParents(to, protoGetParents(from));
  60. protoSetScript(to, protoGetScript(from));
  61. protoSetAbstract(to, protoIsAbstract(from));
  62. Py_XDECREF(to->code);
  63. Py_XINCREF(from->code);
  64. to->code = from->code;
  65. }
  66. PROTO_DATA *protoCopy(PROTO_DATA *data) {
  67. PROTO_DATA *newproto = newProto();
  68. protoCopyTo(data, newproto);
  69. return newproto;
  70. }
  71. STORAGE_SET *protoStore(PROTO_DATA *data) {
  72. STORAGE_SET *set = new_storage_set();
  73. store_string(set, "parents", data->parents);
  74. store_bool (set, "abstract", data->abstract);
  75. store_string(set, "script", bufferString(data->script));
  76. return set;
  77. }
  78. PROTO_DATA *protoRead(STORAGE_SET *set) {
  79. PROTO_DATA *data = newProto();
  80. protoSetParents(data, read_string(set, "parents"));
  81. protoSetAbstract(data, read_bool (set, "abstract"));
  82. protoSetScript(data, read_string(set, "script"));
  83. return data;
  84. }
  85. void protoSetKey(PROTO_DATA *data, const char *key) {
  86. if(data->key) free(data->key);
  87. data->key = strdupsafe(key);
  88. }
  89. void protoSetParents(PROTO_DATA *data, const char *parents) {
  90. if(data->parents) free(data->parents);
  91. data->parents = strdupsafe(parents);
  92. }
  93. void protoSetScript(PROTO_DATA *data, const char *script) {
  94. bufferClear(data->script);
  95. bufferCat(data->script, script);
  96. Py_XDECREF(data->code);
  97. data->code = NULL;
  98. }
  99. void protoSetAbstract(PROTO_DATA *data, bool abstract) {
  100. data->abstract = abstract;
  101. }
  102. const char *protoGetKey(PROTO_DATA *data) {
  103. return data->key;
  104. }
  105. const char *protoGetParents(PROTO_DATA *data) {
  106. return data->parents;
  107. }
  108. bool protoIsAbstract(PROTO_DATA *data) {
  109. return data->abstract;
  110. }
  111. const char *protoGetScript(PROTO_DATA *data) {
  112. return bufferString(data->script);
  113. }
  114. BUFFER *protoGetScriptBuffer(PROTO_DATA *data) {
  115. return data->script;
  116. }
  117. bool protoRunAs(PROTO_DATA *proto, const char *type, const char *as,
  118. void *pynewfunc, void *protoaddfunc, void *protoclassfunc,
  119. void *me) {
  120. // parse and run all of our parents
  121. LIST *parents = parse_keywords(proto->parents);
  122. LIST_ITERATOR *parent_i = newListIterator(parents);
  123. char *one_parent = NULL;
  124. bool parents_ok = TRUE;
  125. // try to run each parent
  126. ITERATE_LIST(one_parent, parent_i) {
  127. PROTO_DATA *parent = NULL;
  128. // does our parent have a locale? If so, find it. If not, use ours
  129. int separator_pos = next_letter_in(one_parent, '@');
  130. if(separator_pos == -1)
  131. parent = worldGetType(gameworld, type,
  132. get_fullkey(one_parent,get_key_locale(proto->key)));
  133. else
  134. parent = worldGetType(gameworld, type, one_parent);
  135. if(parent == NULL) {
  136. log_string("ERROR: could not find parent %s for %s %s.", one_parent,
  137. type, protoGetKey(proto));
  138. parents_ok = FALSE;
  139. }
  140. else if(!protoRun(parent, type, pynewfunc, protoaddfunc, protoclassfunc,me))
  141. parents_ok = FALSE;
  142. // if we had a problem running the proto, report it
  143. if(parents_ok == FALSE)
  144. break;
  145. } deleteListIterator(parent_i);
  146. // do garbage collection for our parent list
  147. deleteListWith(parents, free);
  148. // did we encounter a problem w/ our parents?
  149. if(parents_ok == FALSE)
  150. return FALSE;
  151. // now, do us
  152. PyObject *dict = restricted_script_dict();
  153. PyObject *pyme = ((PyObject *(*)(void *))pynewfunc)(me);
  154. if(protoaddfunc)
  155. ((void (*)(void *, const char *))protoaddfunc)(me, protoGetKey(proto));
  156. if(protoclassfunc)
  157. ((void (*)(void *, const char *))protoclassfunc)(me, as);
  158. PyDict_SetItemString(dict, "me", pyme);
  159. // do we have our own code already, or do we need to compile from source?
  160. if(proto->code == NULL) {
  161. proto->code = run_script_forcode(dict, bufferString(proto->script),
  162. get_key_locale(as));
  163. }
  164. // we already have a code object. Evaluate it.
  165. else {
  166. run_code(proto->code, dict, get_key_locale(as));
  167. if(!last_script_ok())
  168. log_pyerr("Prototype %s terminated with an error:\r\n%s",
  169. proto->key, bufferString(proto->script));
  170. }
  171. // remove us from the dictionary just incase it doesn't GC immediately. It
  172. // happens sometimes if we define a new method in the prototype
  173. PyDict_DelItemString(dict, "me");
  174. // PyDict_SetItemString(dict, "me", Py_None);
  175. // garbage collection
  176. Py_DECREF(dict);
  177. // Py_DECREF(pyme);
  178. return last_script_ok();
  179. }
  180. bool protoRun(PROTO_DATA *proto, const char *type, void *pynewfunc,
  181. void *protoaddfunc, void *protoclassfunc, void *me) {
  182. const char *as = protoGetKey(proto);
  183. return protoRunAs(proto,type,as,pynewfunc,protoaddfunc,protoclassfunc,me);
  184. }
  185. CHAR_DATA *protoMobRun(PROTO_DATA *proto) {
  186. if(protoIsAbstract(proto))
  187. return NULL;
  188. CHAR_DATA *ch = newMobile();
  189. char_exist(ch);
  190. if(protoRun(proto, "mproto", charGetPyFormBorrowed, charAddPrototype, charSetClass, ch))
  191. char_to_game(ch);
  192. else {
  193. // should this be char_unexist? Check to see what difference it makes
  194. extract_mobile(ch);
  195. ch = NULL;
  196. }
  197. return ch;
  198. }
  199. OBJ_DATA *protoObjRun(PROTO_DATA *proto) {
  200. if(protoIsAbstract(proto))
  201. return NULL;
  202. OBJ_DATA *obj = newObj();
  203. obj_exist(obj);
  204. if(protoRun(proto, "oproto", objGetPyFormBorrowed, objAddPrototype, objSetClass, obj))
  205. obj_to_game(obj);
  206. else {
  207. // should this be obj_unexist? Check to see what difference it makes
  208. extract_obj(obj);
  209. obj = NULL;
  210. }
  211. return obj;
  212. }
  213. ROOM_DATA *protoRoomRun(PROTO_DATA *proto) {
  214. if(protoIsAbstract(proto))
  215. return NULL;
  216. ROOM_DATA *room = newRoom();
  217. room_exist(room);
  218. if(protoRun(proto, "rproto", roomGetPyFormBorrowed, roomAddPrototype,roomSetClass,room))
  219. room_to_game(room);
  220. else {
  221. // should this be room_unexist? Check to see what difference it makes
  222. extract_room(room);
  223. room = NULL;
  224. }
  225. return room;
  226. }
  227. ROOM_DATA *protoRoomInstance(PROTO_DATA *proto, const char *as) {
  228. if(protoIsAbstract(proto))
  229. return NULL;
  230. ROOM_DATA *room = newRoom();
  231. room_exist(room);
  232. if(protoRun(proto, "rproto", roomGetPyFormBorrowed, roomAddPrototype,
  233. roomSetClass, room)) {
  234. roomSetClass(room, as);
  235. room_to_game(room);
  236. }
  237. else {
  238. // should this be room_unexist? Check to see what difference it makes
  239. extract_room(room);
  240. room = NULL;
  241. }
  242. return room;
  243. }