--- deliantra/server/plugins/cfperl/cfperl.xs 2006/02/07 03:06:01 1.13 +++ deliantra/server/plugins/cfperl/cfperl.xs 2006/02/07 23:29:55 1.14 @@ -70,10 +70,41 @@ //static int current_command = -999; +static HV *obj_cache; static PerlInterpreter *perl; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// garbage collect some perl objects, if possible +// all objects no longer referenced and empty are +// eligible for destruction. +void +clean_obj_cache () +{ + int todo = 10; + do + { + I32 klen; + char *key; + HE *he = hv_iternext (obj_cache); + + if (he) + { + SV *sv = SvRV (hv_iterval (obj_cache, he)); + + // emopty and unreferened? nuke it + if (SvREFCNT (sv) == 1 && !HvFILL ((HV *)sv)) + { + hv_delete (obj_cache, HeKEY (he), HeKLEN (he), G_DISCARD); + todo++; + } + } + else + break; + } + while (--todo); +} + static SV * newSVptr (void *ptr, const char *klass) { @@ -85,6 +116,27 @@ return sv_bless (newRV_noinc ((SV *)hv), gv_stashpv (klass, 1)); } +static SV * +newSVptr_cached (void *ptr, const char *klass) +{ + SV *sv, **he; + + if (!ptr) + return &PL_sv_undef; + + he = hv_fetch (obj_cache, (char *)&ptr, sizeof (ptr), 0); + + if (he) + sv = *he; + else + { + sv = newSVptr (ptr, klass); + hv_store (obj_cache, (char *)&ptr, sizeof (ptr), sv, 0); + } + + return newSVsv (sv); +} + static void clearSVptr (SV *sv) { @@ -148,15 +200,15 @@ switch (*(int *)cf_object_get_property (obj, CFAPI_OBJECT_PROP_TYPE)) { case MAP: - sv = newSVptr (obj, "cf::object::map"); + sv = newSVptr_cached (obj, "cf::object::map"); break; case PLAYER: - sv = newSVptr (obj, "cf::object::player"); + sv = newSVptr_cached (obj, "cf::object::player"); break; default: - sv = newSVptr (obj, "cf::object"); + sv = newSVptr_cached (obj, "cf::object"); break; } } @@ -359,6 +411,7 @@ registerGlobalEvent (NULL, EVENT_TELL, PLUGIN_NAME, globalEventListener); registerGlobalEvent (NULL, EVENT_MUZZLE, PLUGIN_NAME, globalEventListener); registerGlobalEvent (NULL, EVENT_KICK, PLUGIN_NAME, globalEventListener); + registerGlobalEvent (NULL, EVENT_FREE_OB, PLUGIN_NAME, globalEventListener); char *argv[] = { "", @@ -382,6 +435,10 @@ perl_free (perl); perl = 0; } + else + { + obj_cache = newHV (); + } return 0; } @@ -410,7 +467,11 @@ printf ("Unimplemented for now\n"); break; + case EVENT_MAPENTER: + case EVENT_MAPLEAVE: + case EVENT_FREE_OB: case EVENT_BORN: + case EVENT_REMOVE: context.activator = va_arg (args, object *); break; @@ -424,13 +485,6 @@ break; case EVENT_LOGIN: - pl = va_arg (args, player *); - context.activator = pl->ob; - buf = va_arg (args, char *); - if (buf != 0) - strcpy (context.message, buf); - break; - case EVENT_LOGOUT: pl = va_arg (args, player *); context.activator = pl->ob; @@ -439,24 +493,8 @@ strcpy (context.message, buf); break; - case EVENT_REMOVE: - context.activator = va_arg (args, object *); - break; - case EVENT_SHOUT: - context.activator = va_arg (args, object *); - buf = va_arg (args, char *); - if (buf != 0) - strcpy (context.message, buf); - break; - case EVENT_MUZZLE: - context.activator = va_arg (args, object *); - buf = va_arg (args, char *); - if (buf != 0) - strcpy (context.message, buf); - break; - case EVENT_KICK: context.activator = va_arg (args, object *); buf = va_arg (args, char *); @@ -464,15 +502,11 @@ strcpy (context.message, buf); break; - case EVENT_MAPENTER: - context.activator = va_arg (args, object *); - break; - - case EVENT_MAPLEAVE: - context.activator = va_arg (args, object *); + case EVENT_CLOCK: + clean_obj_cache (); break; - case EVENT_CLOCK: + case EVENT_TELL: break; case EVENT_MAPRESET: @@ -480,14 +514,22 @@ if (buf != 0) strcpy (context.message, buf); break; - - case EVENT_TELL: - break; } va_end (args); - inject_event (&context); + if (context.event_code == EVENT_FREE_OB) + { + SV *sv = hv_delete (obj_cache, (char *)&context.activator, sizeof (object *), 0); + + if (sv) + { + clearSVptr (sv); + SvREFCNT_dec (sv); + } + } + else + inject_event (&context); rv = context.returnvalue; @@ -848,6 +890,24 @@ const_iv (P_NO_ERROR) const_iv (P_OUT_OF_MAP) const_iv (P_NEW_MAP) + + const_iv (UP_OBJ_INSERT) + const_iv (UP_OBJ_REMOVE) + const_iv (UP_OBJ_CHANGE) + const_iv (UP_OBJ_FACE) + + const_iv (INS_NO_MERGE) + const_iv (INS_ABOVE_FLOOR_ONLY) + const_iv (INS_NO_WALK_ON) + const_iv (INS_ON_TOP) + const_iv (INS_BELOW_ORIGINATOR) + const_iv (INS_MAP_LOAD) + + const_iv (WILL_APPLY_HANDLE) + const_iv (WILL_APPLY_TREASURE) + const_iv (WILL_APPLY_EARTHWALL) + const_iv (WILL_APPLY_DOOR) + const_iv (WILL_APPLY_FOOD) }; for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ-- > const_iv; ) @@ -871,6 +931,7 @@ const_event (TRIGGER) const_event (CLOSE) const_event (TIMER) + const_event (MOVE) const_event (BORN) const_event (CLOCK) @@ -887,6 +948,7 @@ const_event (TELL) const_event (MUZZLE) const_event (KICK) + //const_event (FREE_OB) }; AV *av = get_av ("cf::EVENT", 1); @@ -1096,14 +1158,14 @@ croak ("unhandled type '%d' in set_property '%d'", type, idx); } -SV * +void inv (object *obj) PROTOTYPE: $ PPCODE: { object *o; for (o = obj->inv; o; o = o->below) - XPUSHs (newSVcfapi (CFAPI_POBJECT, o)); + XPUSHs (sv_2mortal (newSVcfapi (CFAPI_POBJECT, o))); } int cf_object_get_resistance (object *op, int rtype) @@ -1296,16 +1358,16 @@ #int cf_map_get_flags (mapstruct* map, mapstruct** nmap, I16 x, I16 y, I16 *nx, I16 *ny) -SV * +void at (mapstruct *obj, unsigned int x, unsigned int y) PROTOTYPE: $$$ INIT: - if (x >= MAP_WIDTH (obj) || y >= MAP_HEIGHT (obj)) XSRETURN_UNDEF; + if (x >= MAP_WIDTH (obj) || y >= MAP_HEIGHT (obj)) XSRETURN_EMPTY; PPCODE: { object *o; for (o = GET_MAP_OB (obj, x, y); o; o = o->above) - XPUSHs (newSVcfapi (CFAPI_POBJECT, o)); + XPUSHs (sv_2mortal (newSVcfapi (CFAPI_POBJECT, o))); } SV *