Top Mud Sites Forum Return to TopMudSites.com
Go Back   Top Mud Sites Forum > Mud Development and Administration > MUD Coding
Click here to Register

Reply
 
Thread Tools
Old 05-09-2004, 04:24 PM   #1
Samson
Member
 
Samson's Avatar
 
Join Date: Apr 2002
Location: United Socialist States of America
Home MUD: SmaugMuds.org
Home MUD: Arthmoor MUD Hosting
Posts: 249
Samson is on a distinguished road
I'm having a problem I can't quite pin down. Against many peoples' better judgement I've started down a C++ conversion of the AFKMud codebase. So far that's gone pretty well, even though it's still in the earlier stages. But just today I noticed a pretty serious problem. When doing a hotboot, reloading the object files that were saved prior to the boot creates an infinite loop as it boots up. I believe I've traced it to the function that loads the objects ( logs stop there and go no farther ). I think the obj_to_room conversion is to blame, and as I was examining it, I began to wonder. Just WTF does this thing do anyway? Why does obj_to_room return an OBJ_DATA pointer? It worked perfectly before the conversion, but obviously it's now now. So maybe I'm doing something wrong?

Alternately, maybe I just don't grasp how the obj_to_room code works, so I'm posting what I have here, including the obj_group function as well since that seems to play a key part in what's going on and maybe someone can spot what I've done wrong.

What calls this stuff in the hotboot code:

[code]
obj_from_char( tobj );
tobj = obj_to_room( tobj, room, supermob );
[/quote]

The replacement for the above is indicated below:

[code]
void read_obj_file( char *dirname, char *filename )
{
room_index *room;
FILE *fp;
char fname[256];
int vnum;

vnum = atoi( filename );
snprintf( fname, 256, "%s%s", dirname, filename );

if( !( room = get_room_index( vnum ) ) )
{
bug( "read_obj_file; ARGH! Missing room index for %d!", vnum );
unlink( fname );
return;
}

if ( ( fp = fopen( fname, "r" ) ) != NULL )
{
sh_int iNest;
bool found;
obj_data *tobj, *tobj_next;

rset_supermob( room );
for ( iNest = 0; iNest < MAX_NEST; iNest++ )
rgObjNest[iNest] = NULL;

found = true;
for(;; )
{
char letter;
char *word;

letter = fread_letter( fp );
if( letter == '*' )
{
fread_to_eol( fp );
continue;
}

if( letter != '#' )
{
bug( "%s", "read_obj_file; # not found." );
break;
}

word = fread_word( fp );
if( !str_cmp( word, "OBJECT" ) ) /* Objects */
fread_obj( supermob, fp, OS_CARRY );
else if( !str_cmp( word, "END" ) ) /* Done */
break;
else
{
bug( "read_obj_file; bad section; %s", word );
break;
}
}
FCLOSE( fp );
unlink( fname );
for( tobj = supermob->first_carrying; tobj; tobj = tobj_next )
{
tobj_next = tobj->next_content;
if( tobj->HAS_FLAG( ITEM_ONMAP ) )
{
supermob->SET_ACT_FLAG( ACT_ONMAP );
supermob->map = tobj->map;
supermob->mx = tobj->mx;
supermob->my = tobj->my;
}
tobj->from_char(); <---------- REPLACEMENT
tobj = tobj->to_room( room, supermob ); <------------ REPLACEMENT
supermob->REMOVE_ACT_FLAG( ACT_ONMAP );
supermob->map = -1;
supermob->mx = -1;
supermob->my = -1;
}
release_supermob();
}
else
log_string( "Cannot open obj file" );

return;
}
[/quote]

The old code:

[code]
/*
* If possible group obj2 into obj1 -Thoric
* This code, along with clone_object, obj->count, and special support
* for it implemented throughout handler.c and save.c should show improved
* performance on MUDs with players that hoard tons of potions and scrolls
* as this will allow them to be grouped together both in memory, and in
* the player files.
*/
OBJ_DATA *group_object( OBJ_DATA *obj1, OBJ_DATA *obj2 )
{
if ( !obj1 || !obj2 )
return NULL;
if ( obj1 == obj2 )
return obj1;

if( obj1->pIndexData->vnum == OBJ_VNUM_TREASURE || obj2->pIndexData->vnum == OBJ_VNUM_TREASURE )
return obj2;

if ( obj1->pIndexData == obj2->pIndexData
&& QUICKMATCH( obj1->name, obj2->name )
&& QUICKMATCH( obj1->short_descr, obj2->short_descr )
&& QUICKMATCH( obj1->objdesc, obj2->objdesc )
&& ( obj1->action_desc && obj2->action_desc && QUICKMATCH( obj1->action_desc, obj2->action_desc ) )
&& QUICKMATCH( obj1->socket[0], obj2->socket[0] )
&& QUICKMATCH( obj1->socket[1], obj2->socket[1] )
&& QUICKMATCH( obj1->socket[2], obj2->socket[2] )
&& obj1->item_type == obj2->item_type
&& xSAME_BITS( obj1->extra_flags, obj2->extra_flags )
&& obj1->magic_flags == obj2->magic_flags
&& obj1->wear_flags == obj2->wear_flags
&& obj1->wear_loc == obj2->wear_loc
&& obj1->weight == obj2->weight
&& obj1->cost == obj2->cost
&& obj1->level == obj2->level
&& obj1->timer == obj2->timer
&& obj1->value[0] == obj2->value[0]
&& obj1->value[1] == obj2->value[1]
&& obj1->value[2] == obj2->value[2]
&& obj1->value[3] == obj2->value[3]
&& obj1->value[4] == obj2->value[4]
&& obj1->value[5] == obj2->value[5]
&& obj1->value[6] == obj2->value[6]
&& obj1->value[7] == obj2->value[7]
&& obj1->value[8] == obj2->value[8]
&& obj1->value[9] == obj2->value[9]
&& obj1->value[10] == obj2->value[10]
&& !obj1->first_extradesc && !obj2->first_extradesc
&& !obj1->first_affect && !obj2->first_affect
&& !obj1->first_content && !obj2->first_content
&& obj1->count + obj2->count > 0
&& obj1->map == obj2->map
&& obj1->x == obj2->x
&& obj1->y == obj2->y
&& QUICKMATCH( obj1->seller, obj2->seller )
&& QUICKMATCH( obj1->buyer, obj2->buyer )
&& obj1->bid == obj2->bid ) /* prevent count overflow */
{
obj1->count += obj2->count;
obj1->pIndexData->count += obj2->count; /* to be decremented in */
numobjsloaded += obj2->count; /* extract_obj */
extract_obj( obj2 );
return obj1;
}
return obj2;
}

/*
* Move an obj into a room.
*/
OBJ_DATA *obj_to_room( OBJ_DATA *obj, ROOM_INDEX_DATA *pRoomIndex, CHAR_DATA *ch )
{
OBJ_DATA *otmp, *oret;
sh_int count = obj->count;
sh_int item_type = obj->item_type;
AFFECT_DATA *paf;

for( paf = obj->first_affect; paf; paf = paf->next )
room_affect( pRoomIndex, paf, TRUE );

for( paf = obj->pIndexData->first_affect; paf; paf = paf->next )
room_affect( pRoomIndex, paf, TRUE );

for( otmp = pRoomIndex->first_content; otmp; otmp = otmp->next_content )
if( ( oret = group_object( otmp, obj ) ) == otmp )
{
if( item_type == ITEM_FIRE )
pRoomIndex->light += count;
return oret;
}

LINK( obj, pRoomIndex->first_content, pRoomIndex->last_content, next_content, prev_content );
obj->in_room = pRoomIndex;
obj->carried_by = NULL;
obj->in_obj = NULL;
obj->room_vnum = pRoomIndex->vnum; /* hotboot tracker */
if( item_type == ITEM_FIRE )
pRoomIndex->light += count;
falling++;
obj_fall( obj, FALSE );
falling--;

/* Hoping that this will cover all instances of objects from character to room - Samson 8-22-99 */
if( ch != NULL )
{
if( IS_ACT_FLAG( ch, ACT_ONMAP ) || IS_PLR_FLAG( ch, PLR_ONMAP ) )
{
SET_OBJ_FLAG( obj, ITEM_ONMAP );
obj->map = ch->map;
obj->x = ch->x;
obj->y = ch->y;
}
else
{
REMOVE_OBJ_FLAG( obj, ITEM_ONMAP );
obj->map = -1;
obj->x = -1;
obj->y = -1;
}
}

if( obj->pIndexData->vnum == OBJ_VNUM_CORPSE_PC && falling < 1 )
write_corpses( NULL, obj->short_descr+14, NULL );
return obj;
}
[/quote]

The new code:
[code]
/*
* If possible group obj2 into obj1 -Thoric
* This code, along with clone_object, obj->count, and special support
* for it implemented throughout handler.c and save.c should show improved
* performance on MUDs with players that hoard tons of potions and scrolls
* as this will allow them to be grouped together both in memory, and in
* the player files.
*/
obj_data *obj_data;;group( obj_data *obj2 )
{
if ( !this || !obj2 )
return NULL;

if ( this == obj2 )
return this;

if( pIndexData->vnum == OBJ_VNUM_TREASURE || obj2->pIndexData->vnum == OBJ_VNUM_TREASURE )
return obj2;

if( pIndexData == obj2->pIndexData
&& QUICKMATCH( name, obj2->name )
&& QUICKMATCH( short_descr, obj2->short_descr )
&& QUICKMATCH( objdesc, obj2->objdesc )
&& ( action_desc && obj2->action_desc && QUICKMATCH( action_desc, obj2->action_desc ) )
&& QUICKMATCH( socket[0], obj2->socket[0] )
&& QUICKMATCH( socket[1], obj2->socket[1] )
&& QUICKMATCH( socket[2], obj2->socket[2] )
&& item_type == obj2->item_type
&& xSAME_BITS( extra_flags, obj2->extra_flags )
&& magic_flags == obj2->magic_flags
&& wear_flags == obj2->wear_flags
&& wear_loc == obj2->wear_loc
&& weight == obj2->weight
&& cost == obj2->cost
&& level == obj2->level
&& timer == obj2->timer
&& value[0] == obj2->value[0]
&& value[1] == obj2->value[1]
&& value[2] == obj2->value[2]
&& value[3] == obj2->value[3]
&& value[4] == obj2->value[4]
&& value[5] == obj2->value[5]
&& value[6] == obj2->value[6]
&& value[7] == obj2->value[7]
&& value[8] == obj2->value[8]
&& value[9] == obj2->value[9]
&& value[10] == obj2->value[10]
&& !first_extradesc && !obj2->first_extradesc
&& !first_affect && !obj2->first_affect
&& !first_content && !obj2->first_content
&& count + obj2->count > 0
&& map == obj2->map
&& mx == obj2->mx
&& my == obj2->my
&& QUICKMATCH( seller, obj2->seller )
&& QUICKMATCH( buyer, obj2->buyer )
&& bid == obj2->bid ) /* prevent count overflow */
{
count += obj2->count;
pIndexData->count += obj2->count; /* to be decremented in */
numobjsloaded += obj2->count; /* extract_obj */
obj2->extract();
return this;
}
return obj2;
}

/*
* Move an obj into a room.
*/
obj_data *obj_data;;to_room( room_index *pRoomIndex, char_data *ch )
{
obj_data *otmp, *oret;
sh_int ocount = count;
sh_int oitem_type = item_type;
AFFECT_DATA *paf;

for( paf = first_affect; paf; paf = paf->next )
pRoomIndex->room_affect( paf, true );

for( paf = pIndexData->first_affect; paf; paf = paf->next )
pRoomIndex->room_affect( paf, true );

for( otmp = pRoomIndex->first_content; otmp; otmp = otmp->next_content )
if( ( oret = otmp->group( this ) ) == otmp )
{
if( oitem_type == ITEM_FIRE )
pRoomIndex->light += ocount;
return oret;
}

LINK( this, pRoomIndex->first_content, pRoomIndex->last_content, next_content, prev_content );
in_room = pRoomIndex;
carried_by = NULL;
in_obj = NULL;
room_vnum = pRoomIndex->vnum; /* hotboot tracker */
if( oitem_type == ITEM_FIRE )
pRoomIndex->light += count;
falling++;
fall( false );
falling--;

/* Hoping that this will cover all instances of objects from character to room - Samson 8-22-99 */
if( ch != NULL )
{
if( ch->IS_ACT_FLAG( ACT_ONMAP ) || ch->IS_PLR_FLAG( PLR_ONMAP ) )
{
SET_FLAG( ITEM_ONMAP );
map = ch->map;
mx = ch->mx;
my = ch->my;
}
else
{
REMOVE_FLAG( ITEM_ONMAP );
map = -1;
mx = -1;
my = -1;
}
}

if( pIndexData->vnum == OBJ_VNUM_CORPSE_PC && falling < 1 )
write_corpses( NULL, short_descr+14, NULL );
return this;
}
[/quote]

The obj_data class I've converted to, in case it helps:

[code]
/*
* One object.
*/
class obj_data
{
public;
obj_data() { init_obj_data(); }
~obj_data();

void init_obj_data() { init_memory( &next, &map, sizeof( map ) ); }

/* Internal refs in object.c */
void fall( bool through );
int item_ego();
sh_int get_resistance();
char *oshort();
char *format_to_char( char_data *ch, bool fShort );
void show_list_to_char( char_data *ch, bool fShort, bool fShowNothing );
obj_data *to_char( char_data *ch );
void from_char();
int apply_ac( int iWear );
void from_room();
obj_data *to_room( room_index *pRoomIndex, char_data *ch );
obj_data *to_obj( obj_data *obj_to );
void from_obj();
void extract();
int get_number();
int get_weight();
int get_real_weight();
char *item_type_name();
bool is_trapped();
obj_data *get_trap();
bool extracted();
obj_data *clone();
obj_data *group( obj_data *obj2 );
void split( int num );
void separate();
bool empty( obj_data *destobj, room_index *destroom );
void remove_portal();
char_data *who_carrying();
bool in_magic_container();
void make_scraps();
int hitroll();
char *myobj();
EXTRA_DESCR_DATA *SetOExtra( char *keywords );
bool DelOExtra( char *keywords );

/* External refs in other files */
void armorgen();
void weapongen();

obj_data *next;
obj_data *prev;
obj_data *next_content;
obj_data *prev_content;
obj_data *first_content;
obj_data *last_content;
obj_data *in_obj;
obj_index *pIndexData;
room_index *in_room;
char_data *carried_by;
EXTRA_DESCR_DATA *first_extradesc;
EXTRA_DESCR_DATA *last_extradesc;
AFFECT_DATA *first_affect;
AFFECT_DATA *last_affect;
EXT_BV extra_flags;
struct mob_prog_act_list *mpact; /* mudprogs */
int mpactnum; /* mudprogs */
char *name;
char *short_descr;
char *objdesc;
char *action_desc;
char *owner; /* Who owns this item? Used with personal flag for Sindhae prizes. */
char *seller; /* Who put the item up for auction? */
char *buyer; /* Who made the final bid on the item? */
char *socket[3]; /* Name of rune/gem the item has in each socket - Samson 3-31-02 */
int bid; /* What was the amount of the final bid? */
sh_int day; /* What day of the week was it offered or sold? */
sh_int month; /* What month? */
sh_int year; /* What year? */
sh_int item_type;
unsigned short mpscriptpos;
int magic_flags; /*Need more bitvectors for spells - Scryn*/
int wear_flags;
sh_int wear_loc;
sh_int weight;
int cost;
sh_int level;
sh_int timer;
int value[11]; /* Raised to 11 by Samson on 12-14-02 */
sh_int count; /* support for object grouping */
int rent; /* Oh, and yes, this is being used ;) */
int room_vnum; /* Track it's room vnum for hotbooting and such */
sh_int mx; /* Object coordinates on overland maps - Samson 8-21-99 */
sh_int my;
sh_int map; /* Which map is it on? - Samson 8-21-99 */

bool HAS_FLAG( int bit ) { return( xIS_SET( extra_flags, bit ) ); }
void SET_FLAG( int bit ) { xSET_BIT( extra_flags, bit ); }
void REMOVE_FLAG( int bit ) { xREMOVE_BIT( extra_flags, bit ); }

bool HAS_MFLAG( int flag ) { return( IS_SET( magic_flags, flag ) ); }
void SET_MFLAG( int flag ) { SET_BIT( magic_flags, flag ); }
void REMOVE_MFLAG( int flag ) { REMOVE_BIT( magic_flags, flag ); }

bool CAN_WEAR( int bit ) { return( IS_SET( wear_flags, bit ) ); }
void SET_WEAR( int bit ) { SET_BIT( wear_flags, bit ); }
void REMOVE_WEAR( int bit ) { REMOVE_BIT( wear_flags, bit ); }
};
[/quote]
Samson is offline   Reply With Quote
Old 05-10-2004, 06:44 PM   #2
erdos
 
Posts: n/a
Quote:
Originally Posted by (Samson @ May 09 2004,16:24)
Why does obj_to_room return an OBJ_DATA pointer?
AFKMud, being a SMAUG derivative, has a feature whereby multiple copies of an object will coalesce to save system resources if they're grouped  (thus if you have a sword in inventory and someone gives you an identical sword, the new sword is purged and the old sword gets its "count" parameter incremented).  Obviously, if you want to move an object to the floor and still operate on it afterwards, you must anticipate such behavior.  Code such as
[code] obj_to_room( obj, room);
do_get( ch, obj );[/quote]
will crash if the obj pointer becomes invalid due to the coalescing;  the proper code would be
[code] obj = obj_to_room( obj, room );
do_get( ch, obj );[/quote]
or, if you want, even simply
[code] do_get( ch, obj_to_room( obj, room ) );
[/quote](although this slightly simpler still leaves the obj pointer possibly invalid and thus would have to be the last thing using that pointer)

[note that do_get obviously is misused above; this is done on purpose for the sake of making the results clearer]
  Reply With Quote
Old 05-10-2004, 08:18 PM   #3
Samson
Member
 
Samson's Avatar
 
Join Date: Apr 2002
Location: United Socialist States of America
Home MUD: SmaugMuds.org
Home MUD: Arthmoor MUD Hosting
Posts: 249
Samson is on a distinguished road
Yeah, the grouping thing is basically what I got from it. I think I have that part pretty much figured out. I'm just not sure why the changeover to the C++ code is now causing the infinite loop problem. No doubt it'll turn out to be something horribly obvious too.
Samson is offline   Reply With Quote
Old 05-10-2004, 10:33 PM   #4
erdos
 
Posts: n/a
Quote:
Originally Posted by (Samson @ May 10 2004,20:18)
Yeah, the grouping thing is basically what I got from it. I think I have that part pretty much figured out. I'm just not sure why the changeover to the C++ code is now causing the infinite loop problem. No doubt it'll turn out to be something horribly obvious too.
Why are you trying to OOify obj_to_room?  Given its destructive nature (see above), it does not lend itself well to object oriented programming;  somewhere youve probably got some loop which is getting screwed up by invalid pointers due to a clumsy use of this very clumsy OOP.

...
Actually, why are you making SMAUG OO at all?  It is utterly pointless and a massive waste of time.

EDIT:  Oops, sorry, I meant to say "AFKMud", not "SMAUG" :P   (read:  SMAUG with a couple pages worth of buggy snippets added)
  Reply With Quote
Old 05-10-2004, 11:27 PM   #5
Samson
Member
 
Samson's Avatar
 
Join Date: Apr 2002
Location: United Socialist States of America
Home MUD: SmaugMuds.org
Home MUD: Arthmoor MUD Hosting
Posts: 249
Samson is on a distinguished road
Right. I could have done without the cheap shot. Thanks anyway for at least taking the time to answer.
Samson is offline   Reply With Quote
Reply


Thread Tools


obj_to_room problem - Similar Threads
Thread Thread Starter Forum Replies Last Post
A Java Problem Almondine War MUD Coding 6 10-21-2004 11:17 PM
Same problem Nostrum Newbie Help 3 09-19-2002 08:52 AM
Problem with sprintf Enziet MUD Coding 1 07-18-2002 07:50 PM
heartbeat problem with ldmud f451 MUD Coding 8 06-06-2002 05:06 AM
Code Problem Keljorian MUD Coding 1 06-01-2002 11:11 PM

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off

All times are GMT -4. The time now is 01:29 AM.


Powered by vBulletin® Version 3.6.7
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
Style based on a design by Essilor
Copyright Top Mud Sites.com 2014