Copyover for SWR - aka Hotboot -------------------------------- Original code by Erwin Andreasen for Rom muds. Smaug ports by various authors. Cleanup and revisions for smaug port by Samson of Alsherok Port SWR by Greven of Dark Warriors. Ship saving code by Gavin of Dark Warriors. Terms of Use ------------ 1. You may use this snippet in your code provided that any included comment headers in the code are left intact. You may add your own, but do not take any out. 2. This snippet may not be posted for redistribution on any site without obtaining prior written consent from the Alsherok team and the Dark Warriors team. 3. For support of this snippet, come to Greven first, at either http://darkwars.wolfpaw.net/cgi-bin/ikonboard.cgi or darkwarsmud@hotmail.com. I will do what I can for email support, but the forum is generally a better way to go. If you can't agree to these terms, don't use this code, and don't expect help if something breaks while installing it. Harsh? Hardly. It's tiring when people who come crawling to whine and complain when they haven't bothered to comply with the terms first. What this code does ------------------- The usual copyover code which allows a mud to be rebooted without having to drop the socket connections to the players. This particular port has been cleaned up some and has the proper alterations to allow it to work with several of the snippets I have on my site. It also preserves the locations of all loaded mobs and objects in the game at the time, so it will seem like just a bit of lag for the players. Mobs will even still be wounded. The command has also simply been renamed because "copyover" just sounds funny to me :) - Samson SWR Additions ------------- The biggest addition in this code for SWR is the saving of ships, which Gavin did a marvelous job of. It is virtually seemless. Ships in combat stay in combat, their stats stay the same, hyper space is not interupted, nor is landing or movement. Other additions include support for the OLC shuttle code, which is available from the DW coding team. In addition, support for new home code by Gavin is included. Also added with this is the auto detection upon recovery if the clients support MXP, and to set it appropriately. NOTE: I have removed SOME of the extra code for support of Samson's snippets for ease of installation ( like the rent code, doesn't apply to SWR). If you want the extra support code, the original AFKMUD version is available at http://www.afkmud.com . Installation Instructions ------------------------- 1. Add hotboot.c and hotboot.h to your source code directory, and the files to your makefile. Then under your dist dir, make a hotboot dir. 2. Open mud.h and find the following code: /* * Connected state for a channel. */ typedef enum { CON_PLAYING, CON_GET_NAME, CON_GET_OLD_PASSWORD, CON_CONFIRM_NEW_NAME, CON_GET_NEW_PASSWORD, CON_CONFIRM_NEW_PASSWORD, CON_GET_NEW_SEX, CON_READ_MOTD, CON_GET_NEW_RACE, CON_GET_EMULATION, CON_EDITING, CON_GET_WANT_RIPANSI, CON_TITLE, CON_PRESS_ENTER, CON_WAIT_1, CON_WAIT_2, CON_WAIT_3, CON_ACCEPTED, CON_GET_PKILL, CON_READ_IMOTD, CON_GET_NEW_EMAIL, CON_GET_MSP, CON_GET_NEW_CLASS, CON_ROLL_STATS, CON_STATS_OK } connection_types; Add the con stats and the = to make it look like this: /* * Connected state for a channel. */ typedef enum { CON_GET_NAME = -99, CON_GET_OLD_PASSWORD, CON_CONFIRM_NEW_NAME, CON_GET_NEW_PASSWORD, CON_CONFIRM_NEW_PASSWORD, CON_GET_NEW_SEX, CON_READ_MOTD, CON_GET_NEW_RACE, CON_GET_EMULATION, CON_GET_WANT_RIPANSI, CON_TITLE, CON_PRESS_ENTER, CON_WAIT_1, CON_WAIT_2, CON_WAIT_3, CON_ACCEPTED, CON_GET_PKILL, CON_READ_IMOTD, CON_GET_NEW_EMAIL, CON_GET_MSP, CON_GET_NEW_CLASS, CON_ROLL_STATS, CON_STATS_OK, CON_COPYOVER_RECOVER CON_PLAYING = 0, CON_EDITING } connection_types; Then locate the following code: #define LEVEL_ACOLYTE (MAX_LEVEL - 4) #define LEVEL_NEOPHYTE (MAX_LEVEL - 4) #define LEVEL_AVATAR (MAX_LEVEL - 5) Directly below that, add the following: #include "hotboot.h" Then locate the following line of code: void boot_db args( ( void ) ); Change it to read as follows: void boot_db args( ( bool fCopyOver ) ); Then locate the OBJ_DATA struct and add the following to the end of the structure: int room_vnum; /* hotboot tracker */ Then locate the CHAR_DATA struct and add the following to the end: of the structure int home_vnum; /* hotboot tracker */ Then locate the PC_DATA struct and add the following to the end of the structure: bool hotboot; /* hotboot tracker */ Then locate this line in the save.c section: bool load_char_obj args( ( DESCRIPTOR_DATA *d, char *name, bool preload ) ); Change it to read as follows: bool load_char_obj args( ( DESCRIPTOR_DATA *d, char *name, bool preload, bool copyover ) ); Then locate: void fwrite_obj args( ( CHAR_DATA *ch, OBJ_DATA *obj, FILE *fp, int iNest, sh_int os_type ) ); Change it to read as follows: void fwrite_obj args( ( CHAR_DATA *ch, OBJ_DATA *obj, FILE *fp, int iNest, sh_int os_type, bool hotboot ) ); 3. Open comm.c, find: char lastplayercmd[MAX_INPUT_LENGTH*2]; time_t current_time; /* Time of this pulse */ Below that, add: int port; /* Port number to be used */ Locate the following in function main: int main( int argc, char **argv ) { struct timeval now_time; int port; Change to read: int main( int argc, char **argv ) { struct timeval now_time; bool fCopyOver = !TRUE; Then further down in main, locate the following: /* * Get the port number. */ port = 4000; if ( argc > 1 ) { if ( !is_number( argv[1] ) ) { fprintf( stderr, "Usage: %s [port #]\n", argv[0] ); exit( 1 ); } else if ( ( port = atoi( argv[1] ) ) <= 1024 ) { fprintf( stderr, "Port number must be above 1024.\n" ); exit( 1 ); } } Change it to read as follows: /* * Get the port number. */ port = 4000; if ( argc > 1 ) { if ( !is_number( argv[1] ) ) { fprintf( stderr, "Usage: %s [port #]\n", argv[0] ); exit( 1 ); } else if ( ( port = atoi( argv[1] ) ) <= 1024 ) { fprintf( stderr, "Port number must be above 1024.\n" ); exit( 1 ); } if (argv[2] && argv[2][0]) { fCopyOver = TRUE; control = atoi( argv[3] ); control2 = atoi( argv[4] ); conclient = atoi( argv[5] ); conjava = atoi( argv[6] ); } else fCopyOver = FALSE; } Then locate the following a bit further down: log_string("Booting Database"); boot_db( ); log_string("Initializing socket"); control = init_socket( port ); control2 = init_socket( port+1 ); conclient= init_socket( port+10); conjava = init_socket( port+20); Change that to read as: log_string("Booting Database"); boot_db( fCopyOver ); log_string("Initializing socket"); if (!fCopyOver) /* We have already the port if copyover'ed */ { control = init_socket( port ); control2 = init_socket( port+1 ); conclient= init_socket( port+10); conjava = init_socket( port+20); } Then locate the call to game_loop() and directly ABOVE that, add the following: if( fCopyOver ) { log_string( "Initiating hotboot recovery." ); hotboot_recover(); } 4. Open db.c and locate function boot_db. Find this: /* * Big mama top level function. */ void boot_db( void ) Change it to read as: /* * Big mama top level function. */ void boot_db( bool fCopyOver ) Then locate the following segment: log_string( "Resetting areas" ); area_update( ); Change it to read as follows: if( fCopyOver ) { log_string( "Loading world state..." ); load_world( supermob ); } log_string( "Resetting areas..." ); area_update( ); Locate function create_mobile and find the following line: mob->act = pMobIndex->act; Below that line, add the following: mob->home_vnum = -1; 5. Open handler.c, function char_to_room and find the following line: ch->in_room = pRoomIndex; Add the following lines directly beneath that: if( ch->home_vnum < 1 ) ch->home_vnum = ch->in_room->vnum; Then locate function obj_to_room and find the following segment: obj->in_room = pRoomIndex; obj->carried_by = NULL; obj->in_obj = NULL; Add the following line directly beneath that: obj->room_vnum = pRoomIndex->vnum; /* hotboot tracker */ 6. Open save.c, and find: void fread_char args( ( CHAR_DATA *ch, FILE *fp, bool preload) ); Change that to: void fread_char args( ( CHAR_DATA *ch, FILE *fp, bool preload, bool copyover) ); Locate function fwrite_obj and find this line: void fwrite_obj( CHAR_DATA *ch, OBJ_DATA *obj, FILE *fp, int iNest, sh_int os_type ) Change it to read as follows: void fwrite_obj( CHAR_DATA *ch, OBJ_DATA *obj, FILE *fp, int iNest, sh_int os_type, bool hotboot ) Then locate this segment: /* * Slick recursion to write lists backwards, * so loading them will load in forwards order. */ if ( obj->prev_content && os_type != OS_CORPSE ) fwrite_obj( ch, obj->prev_content, fp, iNest, OS_CARRY ); /* * Castrate storage characters. */ if ( obj->item_type == ITEM_KEY && !IS_OBJ_STAT(obj, ITEM_CLANOBJECT )) return; Change it to read as follows: /* * Slick recursion to write lists backwards, * so loading them will load in forwards order. */ if ( obj->prev_content && os_type != OS_CORPSE ) fwrite_obj( ch, obj->prev_content, fp, iNest, OS_CARRY, hotboot ); /* * Castrate storage characters. */ if( !hotboot ) { if ( obj->item_type == ITEM_KEY && !IS_OBJ_STAT(obj, ITEM_CLANOBJECT )) return; } Then locate this segment: /* Corpse saving. -- Altrag */ fprintf( fp, (os_type == OS_CORPSE ? "#CORPSE\n" : "#OBJECT\n") ); Directly ABOVE that, add this: /* DO NOT save corpses lying on the ground as a hotboot item, they already saved elsewhere! - Samson */ if( hotboot && obj->item_type == ITEM_CORPSE_PC ) return; Then locate this segment: if ( os_type == OS_CORPSE && obj->in_room ) fprintf( fp, "Room %d\n", obj->in_room->vnum ); Change it to read as follows: if ( ( os_type == OS_CORPSE || hotboot ) && obj->in_room ) { fprintf( fp, "Room %d\n", obj->in_room->vnum ); fprintf( fp, "Rvnum %d\n", obj->room_vnum ); } Then locate this segment: fprintf( fp, "End\n\n" ); if ( obj->first_content ) fwrite_obj( ch, obj->last_content, fp, iNest + 1, OS_CARRY ); Change it to read as follows: fprintf( fp, "End\n\n" ); if ( obj->first_content ) fwrite_obj( ch, obj->last_content, fp, iNest + 1, OS_CARRY, hotboot ); Then locate function save_char_obj and find the following: fwrite_char( ch, fp ); if ( ch->first_carrying ) fwrite_obj( ch, ch->last_carrying, fp, 0, OS_CARRY ); Change it to read as follows: fwrite_char( ch, fp ); if ( ch->first_carrying ) fwrite_obj( ch, ch->last_carrying, fp, 0, OS_CARRY, ch->pcdata->hotboot ); Then locate function load_char_obj and find the following: /* * Load a char and inventory into a new ch structure. */ bool load_char_obj( DESCRIPTOR_DATA *d, char *name, bool preload ) Change it to read as follows: /* * Load a char and inventory into a new ch structure. */ bool load_char_obj( DESCRIPTOR_DATA *d, char *name, bool preload, bool copyover ) Then further down in function load_char_obj find the following: ch->pcdata->pagerlen = 24; ch->mob_clan = STRALLOC( "" ); ch->was_sentinel = NULL; ch->plr_home = NULL; Directly below that, add the following: ch->pcdata->hotboot = FALSE; /* Never changed except when PC is saved during hotboot save */ Then locate the following further down: word = fread_word( fp ); if ( !str_cmp( word, "PLAYER" ) ) { fread_char ( ch, fp, preload ); if ( preload ) break; } Change it to read as follows: word = fread_word( fp ); if ( !str_cmp( word, "PLAYER" ) ) { fread_char ( ch, fp, preload, copyover ); if ( preload ) break; } Then locate function fread_obj and find the following: bool fNest; bool fVnum; ROOM_INDEX_DATA *room = NULL; Change that to read as: bool fNest; bool fVnum; ROOM_INDEX_DATA *room; if ( ch ) { room = ch->in_room; if( ch->tempnum == -9999 ) file_ver = 0; } Then locate the following: case 'R': KEY( "Room", room, get_room_index(fread_number(fp)) ); Directly beneath that, add the following: KEY( "Rvnum", obj->room_vnum, fread_number(fp)); Then locate function fread_char and find the following: void fread_char( CHAR_DATA *ch, FILE *fp, bool preload ) { char buf[MAX_STRING_LENGTH]; Change that to read as follows: void fread_char( CHAR_DATA *ch, FILE *fp, bool preload, bool copyover ) { char buf[MAX_STRING_LENGTH]; Then further down, locate the following: if ( !str_cmp( word, "Site" ) ) { if ( !preload ) { sprintf( buf, "Last connected from: %s\n\r", fread_word( fp ) ); send_to_char( buf, ch ); } else fread_to_eol( fp ); fMatch = TRUE; if ( preload ) word = "End"; else break; } Change it to read as follows: if ( !str_cmp( word, "Site" ) ) { if ( !preload && !copyover ) { sprintf( buf, "Last connected from: %s\n\r", fread_word( fp ) ); send_to_char( buf, ch ); } else fread_to_eol( fp ); fMatch = TRUE; if ( preload ) word = "End"; else break; } 7. Search the rest of your code for any other calls to fwrite_obj and load_char_obj. Add a FALSE to the arguments for the calls. In stock SWR, the only calls to fwrite_obj are in act_obj.c and save.c. In stock SWR, the only calls to load_char_obj are in act_wiz.c, comm.c, and save.c. For example, in act_obj, the call to fwrite_obj is in save_clan_room, and should look like: fwrite_obj(ch, contents, fp, 0, OS_CARRY , FALSE); 8. Add the appropriate entries to tables.c for do_hotboot 9. Make clean, recompile. 10. After rebooting, make a 'hotboot' command using cedit, and set this to the level you want. This code has been installed and tested on SWR version 1.0 and SWRFUSS on Linux slackware 9.0. Greven, Head Coder of Dark Warriors Mud http://darkwars.wolfpaw.net telnet://darkwars.wolfpaw.net:4848