123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288 |
- //*****************************************************************************
- //
- // prototype.c
- //
- // generic prototype datastructure for anything that can be generated with a
- // python script (e.g. object, room, character). Supports inheritance from
- // other prototypes.
- //
- //*****************************************************************************
- #include "mud.h"
- #include "utils.h"
- #include "prototype.h"
- #include "storage.h"
- #include "room.h"
- #include "character.h"
- #include "object.h"
- #include "world.h"
- #include "zone.h"
- #include "handler.h"
- //*****************************************************************************
- // mandatory modules
- //*****************************************************************************
- #include "scripts/scripts.h"
- #include "scripts/pyplugs.h"
- #include "scripts/pychar.h"
- #include "scripts/pyroom.h"
- #include "scripts/pyobj.h"
- //*****************************************************************************
- // local datastructures, functions, and variables
- //*****************************************************************************
- struct prototype_data {
- char *key;
- char *parents;
- bool abstract;
- BUFFER *script;
- PyObject *code;
- };
- //*****************************************************************************
- // implementation of prototype.h
- //*****************************************************************************
- PROTO_DATA *newProto(void) {
- PROTO_DATA *data = malloc(sizeof(PROTO_DATA));
- data->key = strdup("");
- data->parents = strdup("");
- data->abstract = TRUE;
- data->script = newBuffer(1);
- data->code = NULL;
- return data;
- }
- void deleteProto(PROTO_DATA *data) {
- if(data->key) free(data->key);
- if(data->parents) free(data->parents);
- if(data->script) deleteBuffer(data->script);
- Py_XDECREF(data->code);
- free(data);
- }
- void protoCopyTo(PROTO_DATA *from, PROTO_DATA *to) {
- protoSetKey(to, protoGetKey(from));
- protoSetParents(to, protoGetParents(from));
- protoSetScript(to, protoGetScript(from));
- protoSetAbstract(to, protoIsAbstract(from));
- Py_XDECREF(to->code);
- Py_XINCREF(from->code);
- to->code = from->code;
- }
- PROTO_DATA *protoCopy(PROTO_DATA *data) {
- PROTO_DATA *newproto = newProto();
- protoCopyTo(data, newproto);
- return newproto;
- }
- STORAGE_SET *protoStore(PROTO_DATA *data) {
- STORAGE_SET *set = new_storage_set();
- store_string(set, "parents", data->parents);
- store_bool (set, "abstract", data->abstract);
- store_string(set, "script", bufferString(data->script));
- return set;
- }
- PROTO_DATA *protoRead(STORAGE_SET *set) {
- PROTO_DATA *data = newProto();
- protoSetParents(data, read_string(set, "parents"));
- protoSetAbstract(data, read_bool (set, "abstract"));
- protoSetScript(data, read_string(set, "script"));
- return data;
- }
- void protoSetKey(PROTO_DATA *data, const char *key) {
- if(data->key) free(data->key);
- data->key = strdupsafe(key);
- }
- void protoSetParents(PROTO_DATA *data, const char *parents) {
- if(data->parents) free(data->parents);
- data->parents = strdupsafe(parents);
- }
- void protoSetScript(PROTO_DATA *data, const char *script) {
- bufferClear(data->script);
- bufferCat(data->script, script);
- Py_XDECREF(data->code);
- data->code = NULL;
- }
- void protoSetAbstract(PROTO_DATA *data, bool abstract) {
- data->abstract = abstract;
- }
- const char *protoGetKey(PROTO_DATA *data) {
- return data->key;
- }
- const char *protoGetParents(PROTO_DATA *data) {
- return data->parents;
- }
- bool protoIsAbstract(PROTO_DATA *data) {
- return data->abstract;
- }
- const char *protoGetScript(PROTO_DATA *data) {
- return bufferString(data->script);
- }
- BUFFER *protoGetScriptBuffer(PROTO_DATA *data) {
- return data->script;
- }
- bool protoRunAs(PROTO_DATA *proto, const char *type, const char *as,
- void *pynewfunc, void *protoaddfunc, void *protoclassfunc,
- void *me) {
- // parse and run all of our parents
- LIST *parents = parse_keywords(proto->parents);
- LIST_ITERATOR *parent_i = newListIterator(parents);
- char *one_parent = NULL;
- bool parents_ok = TRUE;
- // try to run each parent
- ITERATE_LIST(one_parent, parent_i) {
- PROTO_DATA *parent = NULL;
- // does our parent have a locale? If so, find it. If not, use ours
- int separator_pos = next_letter_in(one_parent, '@');
- if(separator_pos == -1)
- parent = worldGetType(gameworld, type,
- get_fullkey(one_parent,get_key_locale(proto->key)));
- else
- parent = worldGetType(gameworld, type, one_parent);
-
- if(parent == NULL) {
- log_string("ERROR: could not find parent %s for %s %s.", one_parent,
- type, protoGetKey(proto));
- parents_ok = FALSE;
- }
- else if(!protoRun(parent, type, pynewfunc, protoaddfunc, protoclassfunc,me))
- parents_ok = FALSE;
- // if we had a problem running the proto, report it
- if(parents_ok == FALSE)
- break;
- } deleteListIterator(parent_i);
- // do garbage collection for our parent list
- deleteListWith(parents, free);
- // did we encounter a problem w/ our parents?
- if(parents_ok == FALSE)
- return FALSE;
- // now, do us
- PyObject *dict = restricted_script_dict();
- PyObject *pyme = ((PyObject *(*)(void *))pynewfunc)(me);
- if(protoaddfunc)
- ((void (*)(void *, const char *))protoaddfunc)(me, protoGetKey(proto));
- if(protoclassfunc)
- ((void (*)(void *, const char *))protoclassfunc)(me, as);
- PyDict_SetItemString(dict, "me", pyme);
- // do we have our own code already, or do we need to compile from source?
- if(proto->code == NULL) {
- proto->code = run_script_forcode(dict, bufferString(proto->script),
- get_key_locale(as));
- }
- // we already have a code object. Evaluate it.
- else {
- run_code(proto->code, dict, get_key_locale(as));
-
- if(!last_script_ok())
- log_pyerr("Prototype %s terminated with an error:\r\n%s",
- proto->key, bufferString(proto->script));
- }
- // remove us from the dictionary just incase it doesn't GC immediately. It
- // happens sometimes if we define a new method in the prototype
- PyDict_DelItemString(dict, "me");
- // PyDict_SetItemString(dict, "me", Py_None);
- // garbage collection
- Py_DECREF(dict);
- // Py_DECREF(pyme);
- return last_script_ok();
- }
- bool protoRun(PROTO_DATA *proto, const char *type, void *pynewfunc,
- void *protoaddfunc, void *protoclassfunc, void *me) {
- const char *as = protoGetKey(proto);
- return protoRunAs(proto,type,as,pynewfunc,protoaddfunc,protoclassfunc,me);
- }
- CHAR_DATA *protoMobRun(PROTO_DATA *proto) {
- if(protoIsAbstract(proto))
- return NULL;
- CHAR_DATA *ch = newMobile();
- char_exist(ch);
- if(protoRun(proto, "mproto", charGetPyFormBorrowed, charAddPrototype, charSetClass, ch))
- char_to_game(ch);
- else {
- // should this be char_unexist? Check to see what difference it makes
- extract_mobile(ch);
- ch = NULL;
- }
- return ch;
- }
- OBJ_DATA *protoObjRun(PROTO_DATA *proto) {
- if(protoIsAbstract(proto))
- return NULL;
- OBJ_DATA *obj = newObj();
- obj_exist(obj);
- if(protoRun(proto, "oproto", objGetPyFormBorrowed, objAddPrototype, objSetClass, obj))
- obj_to_game(obj);
- else {
- // should this be obj_unexist? Check to see what difference it makes
- extract_obj(obj);
- obj = NULL;
- }
- return obj;
- }
- ROOM_DATA *protoRoomRun(PROTO_DATA *proto) {
- if(protoIsAbstract(proto))
- return NULL;
- ROOM_DATA *room = newRoom();
- room_exist(room);
- if(protoRun(proto, "rproto", roomGetPyFormBorrowed, roomAddPrototype,roomSetClass,room))
- room_to_game(room);
- else {
- // should this be room_unexist? Check to see what difference it makes
- extract_room(room);
- room = NULL;
- }
- return room;
- }
- ROOM_DATA *protoRoomInstance(PROTO_DATA *proto, const char *as) {
- if(protoIsAbstract(proto))
- return NULL;
- ROOM_DATA *room = newRoom();
- room_exist(room);
- if(protoRun(proto, "rproto", roomGetPyFormBorrowed, roomAddPrototype,
- roomSetClass, room)) {
- roomSetClass(room, as);
- room_to_game(room);
- }
- else {
- // should this be room_unexist? Check to see what difference it makes
- extract_room(room);
- room = NULL;
- }
- return room;
- }
|