diff -r -N -c socketmud/src/Makefile socketmud-event/src/Makefile *** socketmud/src/Makefile Thu Oct 2 13:07:32 2003 --- socketmud-event/src/Makefile Thu Oct 2 13:07:51 2003 *************** *** 2,9 **** C_FLAGS = -Wall -O -pedantic L_FLAGS = -lz -lpthread -lcrypt ! O_FILES = socket.o io.o strings.o update.o utils.o interpret.o help.o \ ! action_safe.o mccp.o save.o all: $(O_FILES) rm -f SocketMud --- 2,9 ---- C_FLAGS = -Wall -O -pedantic L_FLAGS = -lz -lpthread -lcrypt ! O_FILES = socket.o io.o strings.o utils.o interpret.o help.o \ ! action_safe.o mccp.o save.o event.o event-handler.o all: $(O_FILES) rm -f SocketMud diff -r -N -c socketmud/src/event-handler.c socketmud-event/src/event-handler.c *** socketmud/src/event-handler.c Thu Jan 1 01:00:00 1970 --- socketmud-event/src/event-handler.c Thu Oct 2 13:07:51 2003 *************** *** 0 **** --- 1,439 ---- + #include + #include + #include + #include + #include + + /* include main header file */ + #include "mud.h" + + EVENT_DATA *eventqueue[MAX_EVENT_HASH]; + EVENT_DATA *eventlast[MAX_EVENT_HASH]; + EVENT_DATA *pEventNext = NULL, *event_free = NULL, *event_free_last = NULL; + EVENT_DATA *global_event_list = NULL; + EVENT_DATA *global_event_last = NULL; + int current_bucket = 0; + + /* function :: enqueue_event() + * arguments :: the event to enqueue and the delay time. + * ====================================================== + * This function takes an event which has _already_ been + * linked locally to it's owner, and places it in the + * event queue, thus making it execute in the given time. + */ + bool enqueue_event(EVENT_DATA *event, int game_pulses) + { + int bucket, passes; + + /* check to see if the event has been attached to an owner */ + if (event->ownertype == EVENT_UNOWNED) + { + bug("enqueue_event: event type %d with no owner.", event->type); + return FALSE; + } + + /* An event must be enqueued into the future */ + if (game_pulses < 1) + game_pulses = 1; + + /* calculate which bucket to put the event in, + * and how many passes the event must stay in the queue. + */ + bucket = (game_pulses + current_bucket) % MAX_EVENT_HASH; + passes = game_pulses / MAX_EVENT_HASH; + + /* let the event store this information */ + event->passes = passes; + event->bucket = bucket; + + /* attach the event in the queue */ + LINK_GLOBAL(event, eventqueue[bucket], eventlast[bucket]); + + /* success */ + return TRUE; + } + + /* function :: free_event() + * arguments :: the event to be free'ed. + * ====================================================== + * This function recycles events. Can be safely called + * on any dequeued event. + */ + void free_event(EVENT_DATA *event) + { + /* free memory */ + free(event->argument); + + /* attach data to the free list */ + LINK_GLOBAL(event, event_free, event_free_last); + } + + /* function :: dequeue_event() + * arguments :: the event to dequeue. + * ====================================================== + * This function takes an event which has _already_ been + * enqueued, and removes it both from the event queue, and + * from the owners local list. This function is usually + * called when the owner is destroyed or after the event + * is executed. + */ + void dequeue_event(EVENT_DATA *event) + { + /* dequeue from the bucket */ + UNLINK_GLOBAL(event, eventqueue[event->bucket], eventlast[event->bucket], + "dequeue_event: event type %d not found in global queue.", event->type); + + /* update global next pointer if we have to */ + if (event == pEventNext) + pEventNext = pEventNext->next_global; + + /* dequeue from owners local list */ + switch(event->ownertype) + { + default: + bug("dequeue_event: event type %d has no owner.", event->type); + break; + case EVENT_OWNER_GAME: + UNLINK_LOCAL(event, global_event_list, global_event_last, + "dequeue_event (game): event type %d not found in local list.", event->type); + break; + case EVENT_OWNER_DMOB: + UNLINK_LOCAL(event, event->owner.dMob->event_first, event->owner.dMob->event_last, + "dequeue_event (mobile): event type %d not found in local list.", event->type); + break; + case EVENT_OWNER_DSOCKET: + UNLINK_LOCAL(event, event->owner.dSock->event_first, event->owner.dSock->event_last, + "dequeue_event (socket): event type %d not found in local list.", event->type); + break; + } + + /* free the data */ + free_event(event); + } + + /* function :: alloc_event() + * arguments :: none + * ====================================================== + * This function allocates memory for an event, and + * makes sure it's values are set to default. + */ + EVENT_DATA *alloc_event() + { + EVENT_DATA *event; + + if (event_free) + { + event = event_free; + + UNLINK_GLOBAL(event, event_free, event_free_last, + "alloc_event: %s", "event not found in local list."); + } + else + { + event = calloc(1, sizeof(*event)); + } + + /* clear the event */ + event->fun = NULL; + event->argument = NULL; + event->owner.dMob = NULL; /* only need to NULL one of the union members */ + event->passes = 0; + event->bucket = 0; + event->ownertype = EVENT_UNOWNED; + event->type = EVENT_NONE; + + /* return the allocated and cleared event */ + return event; + } + + /* function :: init_event_queue() + * arguments :: what section to initialize. + * ====================================================== + * This function is used to initialize the event queue, + * and the first section should be initialized at boot, + * the second section should be called after all areas, + * players, monsters, etc has been loaded into memory, + * and it should contain all maintanence events. + */ + void init_event_queue(int section) + { + EVENT_DATA *event; + int i; + + if (section == 1) + { + for (i = 0; i < MAX_EVENT_HASH; i++) + { + eventqueue[i] = NULL; + eventlast[i] = NULL; + } + } + else if (section == 2) + { + event = alloc_event(); + event->fun = &event_game_tick; + event->type = EVENT_GAME_TICK; + add_event_game(event, 10 * 60 * PULSES_PER_SECOND); + } + } + + /* function :: heartbeat() + * arguments :: none + * ====================================================== + * This function is called once per game pulse, and it will + * check the queue, and execute any pending events, which + * has been enqueued to execute at this specific time. + */ + void heartbeat() + { + EVENT_DATA *event; + + /* current_bucket should be global, it is also used in enqueue_event + * to figure out what bucket to place the new event in. + */ + current_bucket = (current_bucket + 1) % MAX_EVENT_HASH; + + for (event = eventqueue[current_bucket]; event; event = pEventNext) + { + /* pEventNext is also global, should an event cause other + * events to be dequeued, it is vital that we known which + * event is actually next. Remember to update this pointer in + * dequeue_event(). + */ + pEventNext = event->next_global; + + /* Here we use the event->passes integer, to keep track of + * how many times we have ignored this event. + */ + if (event->passes-- > 0) continue; + + /* execute event and extract if needed. We assume that all + * event functions are of the following prototype + * + * bool event_function ( EVENT_DATA *event ); + * + * Any event returning TRUE is not dequeued, it is assumed + * that the event has dequeued itself. + */ + if (!((*event->fun)(event))) + dequeue_event(event); + } + } + + /* function :: add_event_mobile() + * arguments :: the event, the owner and the delay + * ====================================================== + * This function attaches an event to a mobile, and sets + * all the correct values, and makes sure it is enqueued + * into the event queue. + */ + void add_event_mobile(EVENT_DATA *event, D_MOBILE *dMob, int delay) + { + /* check to see if the event has a type */ + if (event->type == EVENT_NONE) + { + bug("add_event_mobile: no type."); + return; + } + + /* check to see of the event has a callback function */ + if (event->fun == NULL) + { + bug("add_event_mobile: event type %d has no callback function.", event->type); + return; + } + + /* set the correct variables for this event */ + event->ownertype = EVENT_OWNER_DMOB; + event->owner.dMob = dMob; + + /* attach the event to the mobiles local list */ + LINK_LOCAL(event, dMob->event_first, dMob->event_last); + + /* attempt to enqueue the event */ + if (enqueue_event(event, delay) == FALSE) + bug("add_event_mobile: event type %d failed to be enqueued.", event->type); + } + + /* function :: add_event_socket() + * arguments :: the event, the owner and the delay + * ====================================================== + * This function attaches an event to a socket, and sets + * all the correct values, and makes sure it is enqueued + * into the event queue. + */ + void add_event_socket(EVENT_DATA *event, D_SOCKET *dSock, int delay) + { + /* check to see if the event has a type */ + if (event->type == EVENT_NONE) + { + bug("add_event_socket: no type."); + return; + } + + /* check to see of the event has a callback function */ + if (event->fun == NULL) + { + bug("add_event_socket: event type %d has no callback function.", event->type); + return; + } + + /* set the correct variables for this event */ + event->ownertype = EVENT_OWNER_DSOCKET; + event->owner.dSock = dSock; + + /* attach the event to the sockets local list */ + LINK_LOCAL(event, dSock->event_first, dSock->event_last); + + /* attempt to enqueue the event */ + if (enqueue_event(event, delay) == FALSE) + bug("add_event_socket: event type %d failed to be enqueued.", event->type); + } + + /* function :: add_event_game() + * arguments :: the event and the delay + * ====================================================== + * This funtion attaches an event to the list og game + * events, and makes sure it's enqueued with the correct + * delay time. + */ + void add_event_game(EVENT_DATA *event, int delay) + { + /* check to see if the event has a type */ + if (event->type == EVENT_NONE) + { + bug("add_event_game: no type."); + return; + } + + /* check to see of the event has a callback function */ + if (event->fun == NULL) + { + bug("add_event_game: event type %d has no callback function.", event->type); + return; + } + + /* set the correct variables for this event */ + event->ownertype = EVENT_OWNER_GAME; + + /* attach the event to the gamelist */ + LINK_LOCAL(event, global_event_list, global_event_last); + + /* attempt to enqueue the event */ + if (enqueue_event(event, delay) == FALSE) + bug("add_event_game: event type %d failed to be enqueued.", event->type); + } + + /* function :: event_isset_socket() + * arguments :: the socket and the type of event + * ====================================================== + * This function checks to see if a given type of event + * is enqueued/attached to a given socket, and if it is, + * it will return a pointer to this event. + */ + EVENT_DATA *event_isset_socket(D_SOCKET *dSock, int type) + { + EVENT_DATA *event; + + for (event = dSock->event_first; event; event = event->next_local) + { + if (event->type == type) + return event; + } + + /* no event found, return NULL */ + return NULL; + } + + /* function :: event_isset_mobile() + * arguments :: the mobile and the type of event + * ====================================================== + * This function checks to see if a given type of event + * is enqueued/attached to a given mobile, and if it is, + * it will return a pointer to this event. + */ + EVENT_DATA *event_isset_mobile(D_MOBILE *dMob, int type) + { + EVENT_DATA *event; + + for (event = dMob->event_first; event; event = event->next_local) + { + if (event->type == type) + return event; + } + + /* no event found, return NULL */ + return NULL; + } + + /* function :: strip_event_socket() + * arguments :: the socket and the type of event + * ====================================================== + * This function will dequeue all events of a given type + * from the given socket. + */ + void strip_event_socket(D_SOCKET *dSock, int type) + { + EVENT_DATA *event, *event_next; + + for (event = dSock->event_first; event; event = event_next) + { + event_next = event->next_local; + + if (event->type == type) + dequeue_event(event); + } + } + + /* function :: strip_event_mobile() + * arguments :: the mobile and the type of event + * ====================================================== + * This function will dequeue all events of a given type + * from the given mobile. + */ + void strip_event_mobile(D_MOBILE *dMob, int type) + { + EVENT_DATA *event, *event_next; + + for (event = dMob->event_first; event; event = event_next) + { + event_next = event->next_local; + + if (event->type == type) + dequeue_event(event); + } + } + + /* function :: init_events_mobile() + * arguments :: the mobile + * ====================================================== + * this function should be called when a player is loaded, + * it will initialize all updating events for that player. + */ + void init_events_player(D_MOBILE *dMob) + { + EVENT_DATA *event; + + /* save the player every 2 minutes */ + event = alloc_event(); + event->fun = &event_mobile_save; + event->type = EVENT_MOBILE_SAVE; + add_event_mobile(event, dMob, 2 * 60 * PULSES_PER_SECOND); + } + + /* function :: init_events_socket() + * arguments :: the mobile + * ====================================================== + * this function should be called when a socket connects, + * it will initialize all updating events for that socket. + */ + void init_events_socket(D_SOCKET *dSock) + { + EVENT_DATA *event; + + /* disconnect/idle */ + event = alloc_event(); + event->fun = &event_socket_idle; + event->type = EVENT_SOCKET_IDLE; + add_event_socket(event, dSock, 5 * 60 * PULSES_PER_SECOND); + } diff -r -N -c socketmud/src/event.c socketmud-event/src/event.c *** socketmud/src/event.c Thu Jan 1 01:00:00 1970 --- socketmud-event/src/event.c Thu Oct 2 13:07:51 2003 *************** *** 0 **** --- 1,80 ---- + #include + #include + #include + #include + + /* include main header file */ + #include "mud.h" + + /* event_game_tick is just to show how to make global events + * which can be used to update the game. + */ + bool event_game_tick(EVENT_DATA *event) + { + D_MOBILE *dMob; + + /* send a tick message to everyone */ + for (dMob = dmobile_list; dMob; dMob = dMob->next) + { + text_to_mobile(dMob, "Tick!\n\r"); + } + + /* enqueue another game tick in 10 minutes */ + event = alloc_event(); + event->fun = &event_game_tick; + event->type = EVENT_GAME_TICK; + add_event_game(event, 10 * 60 * PULSES_PER_SECOND); + + return FALSE; + } + + bool event_mobile_save(EVENT_DATA *event) + { + D_MOBILE *dMob; + + /* Check to see if there is an owner of this event. + * If there is no owner, we return TRUE, because + * it's the safest - and post a bug message. + */ + if ((dMob = event->owner.dMob) == NULL) + { + bug("event_mobile_save: no owner."); + return TRUE; + } + + /* save the actual player file */ + save_player(dMob); + + /* enqueue a new event to save the pfile in 2 minutes */ + event = alloc_event(); + event->fun = &event_mobile_save; + event->type = EVENT_MOBILE_SAVE; + add_event_mobile(event, dMob, 2 * 60 * PULSES_PER_SECOND); + + return FALSE; + } + + bool event_socket_idle(EVENT_DATA *event) + { + D_SOCKET *dSock; + + /* Check to see if there is an owner of this event. + * If there is no owner, we return TRUE, because + * it's the safest - and post a bug message. + */ + if ((dSock = event->owner.dSock) == NULL) + { + bug("event_socket_idle: no owner."); + return TRUE; + } + + /* tell the socket that it has idled out, and close it */ + text_to_socket(dSock, "You have idled out...\n\n\r"); + close_socket(dSock, FALSE); + + /* since we closed the socket, all events owned + * by that socket has been dequeued, and we need + * to return TRUE, so the caller knows this. + */ + return TRUE; + } diff -r -N -c socketmud/src/event.h socketmud-event/src/event.h *** socketmud/src/event.h Thu Jan 1 01:00:00 1970 --- socketmud-event/src/event.h Thu Oct 2 13:07:51 2003 *************** *** 0 **** --- 1,170 ---- + /* event.h + * + * This file contains the event data struture, global variables + * and specially defined values like MAX_EVENT_HASH. + */ + + /* the size of the event queue */ + #define MAX_EVENT_HASH 128 + + /* the different types of owners */ + #define EVENT_UNOWNED 0 + #define EVENT_OWNER_NONE 1 + #define EVENT_OWNER_DSOCKET 2 + #define EVENT_OWNER_DMOB 3 + #define EVENT_OWNER_GAME 4 + + /* the NULL event type */ + #define EVENT_NONE 0 + + /* Mobile events are given a type value here. + * Each value should be unique and explicit, + * besides that, there are no restrictions. + */ + #define EVENT_MOBILE_SAVE 1 + + /* Socket events are given a type value here. + * Each value should be unique and explicit, + * besides that, there are no restrictions. + */ + #define EVENT_SOCKET_IDLE 1 + + /* Game events are given a type value here. + * Each value should be unique and explicit, + * besides that, there are no restrictions + */ + #define EVENT_GAME_TICK 1 + + /* the event prototype */ + typedef bool EVENT_FUN ( EVENT_DATA *event ); + + /* a couple of linked list macro's */ + #define LINK_GLOBAL(item, list, last) \ + { \ + if (last == NULL) \ + { \ + last = item; \ + list = item; \ + item->next_global = NULL; \ + item->prev_global = NULL; \ + } \ + else \ + { \ + item->next_global = list; \ + item->prev_global = NULL; \ + list->prev_global = item; \ + list = item; \ + } \ + } + #define LINK_LOCAL(item, list, last) \ + { \ + if (last == NULL) \ + { \ + last = item; \ + list = item; \ + item->next_local = NULL; \ + item->prev_local = NULL; \ + } \ + else \ + { \ + item->next_local = list; \ + item->prev_local = NULL; \ + list->prev_local = item; \ + list = item; \ + } \ + } + #define UNLINK_GLOBAL(item, list, last, bugmess, bugarg) \ + { \ + if (last == list) \ + { \ + last = NULL; \ + list = NULL; \ + } \ + else if (item == list) \ + { \ + list = item->next_global; \ + item->next_global->prev_global = NULL; \ + } \ + else if (item == last) \ + { \ + last = item->prev_global; \ + item->prev_global->next_global = NULL; \ + } \ + else if (!item->prev_global || !item->next_global) \ + { \ + bug(bugmess, bugarg); \ + } \ + else \ + { \ + item->prev_global->next_global = item->next_global; \ + item->next_global->prev_global = item->prev_global; \ + } \ + } + #define UNLINK_LOCAL(item, list, last, bugmess, bugarg) \ + { \ + if (last == list) \ + { \ + last = NULL; \ + list = NULL; \ + } \ + else if (item == list) \ + { \ + list = item->next_local; \ + item->next_local->prev_local = NULL; \ + } \ + else if (item == last) \ + { \ + last = item->prev_local; \ + item->prev_local->next_local = NULL; \ + } \ + else if (!item->prev_local || !item->next_local) \ + { \ + bug(bugmess, bugarg); \ + } \ + else \ + { \ + item->prev_local->next_local = item->next_local; \ + item->next_local->prev_local = item->prev_local; \ + } \ + } + + /* the event structure */ + struct event_data + { + EVENT_DATA * next_global; /* next event in this hash bucket */ + EVENT_DATA * prev_global; /* prev event in this hash bucket */ + EVENT_DATA * next_local; /* next event for owner */ + EVENT_DATA * prev_local; /* prev event for owner */ + EVENT_FUN * fun; /* the function being called */ + char * argument; /* the text argument given (if any) */ + sh_int passes; /* how long before this event executes */ + sh_int type; /* event type EVENT_XXX_YYY */ + sh_int ownertype; /* type of owner (unlinking req) */ + sh_int bucket; /* which bucket is this event in */ + + union + { /* this is the owner of the event, we */ + D_MOBILE * dMob; /* use a union to make sure any of the */ + D_SOCKET * dSock; /* types can be used for an event. */ + } owner; + }; + + /* functions which can be accessed outside event-handler.c */ + EVENT_DATA *alloc_event ( void ); + EVENT_DATA *event_isset_socket ( D_SOCKET *dSock, int type ); + EVENT_DATA *event_isset_mobile ( D_MOBILE *dMob, int type ); + void dequeue_event ( EVENT_DATA *event ); + void init_event_queue ( int section ); + void init_events_player ( D_MOBILE *dMob ); + void init_events_socket ( D_SOCKET *dSock ); + void heartbeat ( void ); + void add_event_mobile ( EVENT_DATA *event, D_MOBILE *dMob, int delay ); + void add_event_socket ( EVENT_DATA *event, D_SOCKET *dSock, int delay ); + void add_event_game ( EVENT_DATA *event, int delay ); + void strip_event_socket ( D_SOCKET *dSock, int type ); + void strip_event_mobile ( D_MOBILE *dMob, int type ); + + /* all events should be defined here */ + bool event_mobile_save ( EVENT_DATA *event ); + bool event_socket_idle ( EVENT_DATA *event ); + bool event_game_tick ( EVENT_DATA *event ); diff -r -N -c socketmud/src/mud.h socketmud-event/src/mud.h *** socketmud/src/mud.h Thu Oct 2 13:07:32 2003 --- socketmud-event/src/mud.h Thu Oct 2 13:07:51 2003 *************** *** 106,117 **** --- 106,120 ---- typedef struct dMobile D_MOBILE; typedef struct help_data HELP_DATA; typedef struct lookup_data LOOKUP_DATA; + typedef struct event_data EVENT_DATA; /* the actual structures */ struct dSocket { D_SOCKET * next; D_MOBILE * player; + EVENT_DATA * event_first; + EVENT_DATA * event_last; char * hostname; char inbuf[MAX_BUFFER]; char outbuf[MAX_OUTPUT]; *************** *** 130,135 **** --- 133,140 ---- { D_MOBILE * next; D_SOCKET * socket; + EVENT_DATA * event_first; + EVENT_DATA * event_last; char * name; char * password; sh_int level; *************** *** 163,168 **** --- 168,176 ---- int size; /* The allocated size of data */ } BUFFER; + /* here we include external structure headers */ + #include "event.h" + /****************************** * End of new structures * ******************************/ *************** *** 263,273 **** int bprintf ( BUFFER *buffer, char *fmt, ... ); /* - * update.c - */ - void update_handler ( void ); - - /* * help.c */ bool check_help ( D_M *dMob, char *helpfile ); --- 271,276 ---- diff -r -N -c socketmud/src/mud.h~ socketmud-event/src/mud.h~ *** socketmud/src/mud.h~ Thu Jan 1 01:00:00 1970 --- socketmud-event/src/mud.h~ Thu Oct 2 13:06:53 2003 *************** *** 0 **** --- 1,321 ---- + /* + * This is the main headerfile + */ + + #ifndef MUD_H + #define MUD_H + + #include + #include + #include + + /*********************** + * Standard defintions * + ***********************/ + + /* define TRUE and FALSE */ + #ifndef FALSE + #define FALSE 0 + #endif + #ifndef TRUE + #define TRUE 1 + #endif + + #define eTHIN 0 + #define eBOLD 1 + + /* A few globals */ + #define PULSES_PER_SECOND 4 /* must divide 1000 : 4, 5 or 8 works */ + #define MAX_BUFFER 1024 /* seems like a decent amount */ + #define MAX_OUTPUT 2048 /* well shoot me if it isn't enough */ + #define MAX_HELP_ENTRY 4096 /* roughly 40 lines of blocktext */ + #define MUDPORT 9009 /* just set whatever port you want */ + #define FILE_TERMINATOR "EOF" /* end of file marker */ + #define COPYOVER_FILE "../txt/copyover.dat" /* tempfile to store copyover data */ + #define EXE_FILE "../src/SocketMud" /* the name of the mud binary */ + + /* Connection States */ + #define STATE_NEW_NAME 0 + #define STATE_NEW_PASSWORD 1 + #define STATE_VERIFY_PASSWORD 2 + #define STATE_ASK_PASSWORD 3 + #define STATE_PLAYING 4 + #define STATE_CLOSED 5 /* should always be the last state */ + + /* Thread States */ + #define TSTATE_LOOKUP 0 /* Socket is in host_lookup */ + #define TSTATE_DONE 1 /* The lookup is done. */ + #define TSTATE_WAIT 2 /* Closed while in thread. */ + #define TSTATE_CLOSED 3 /* Closed, ready to be recycled. */ + + /* player levels */ + #define LEVEL_GUEST 1 /* Dead players and actual guests */ + #define LEVEL_PLAYER 2 /* Almost everyone is this level */ + #define LEVEL_ADMIN 3 /* Any admin without shell access */ + #define LEVEL_GOD 4 /* Any admin with shell access */ + + /* Communication Ranges */ + #define COMM_LOCAL 0 /* same room only */ + #define COMM_LOG 10 /* admins only */ + + /* define simple types */ + typedef unsigned char bool; + typedef short int sh_int; + + + /****************************** + * End of standard definitons * + ******************************/ + + /*********************** + * Defintion of Macros * + ***********************/ + + #define UMIN(a, b) ((a) < (b) ? (a) : (b)) + #define IS_ADMIN(dMob) ((dMob->level) > LEVEL_PLAYER ? TRUE : FALSE) + #define IREAD(sKey, sPtr) \ + { \ + if (compares(sKey, word)) \ + { \ + int sValue = fread_number(fp); \ + sPtr = sValue; \ + found = TRUE; \ + break; \ + } \ + } + #define SREAD(sKey, sPtr) \ + { \ + if (compares(sKey, word)) \ + { \ + sPtr = fread_string(fp); \ + found = TRUE; \ + break; \ + } \ + } + + /*********************** + * End of Macros * + ***********************/ + + /****************************** + * New structures * + ******************************/ + + /* type defintions */ + typedef struct dSocket D_SOCKET; + typedef struct dMobile D_MOBILE; + typedef struct help_data HELP_DATA; + typedef struct lookup_data LOOKUP_DATA; + + /* the actual structures */ + struct dSocket + { + D_SOCKET * next; + D_MOBILE * player; + char * hostname; + char inbuf[MAX_BUFFER]; + char outbuf[MAX_OUTPUT]; + char next_command[MAX_BUFFER]; + bool bust_prompt; + sh_int lookup_status; + sh_int state; + sh_int control; + sh_int top_output; + unsigned char compressing; /* MCCP support */ + z_stream * out_compress; /* MCCP support */ + unsigned char * out_compress_buf; /* MCCP support */ + }; + + struct dMobile + { + D_MOBILE * next; + D_SOCKET * socket; + char * name; + char * password; + sh_int level; + }; + + struct help_data + { + HELP_DATA * next; + time_t load_time; + char * keyword; + char * text; + }; + + struct lookup_data + { + D_SOCKET * dsock; /* the socket we wish to do a hostlookup on */ + char * buf; /* the buffer it should be stored in */ + }; + + struct typCmd + { + char * cmd_name; + void (* cmd_funct)(D_MOBILE *dMOb, char *arg); + sh_int level; + }; + + typedef struct buffer_type + { + char * data; /* The data */ + int len; /* The current len of the buffer */ + int size; /* The allocated size of data */ + } BUFFER; + + /****************************** + * End of new structures * + ******************************/ + + /*************************** + * Global Variables * + ***************************/ + + extern D_SOCKET * dsock_free; /* the socket free list */ + extern D_SOCKET * dsock_list; /* the linked list of active sockets */ + extern D_MOBILE * dmobile_free; /* the mobile free list */ + extern D_MOBILE * dmobile_list; /* the mobile list of active mobiles */ + extern HELP_DATA * help_list; /* the linked list of help files */ + extern const struct typCmd tabCmd[]; /* the command table */ + extern bool shut_down; /* used for shutdown */ + extern char * greeting; /* the welcome greeting */ + extern char * motd; /* the MOTD help file */ + extern int control; /* boot control socket thingy */ + extern time_t current_time; /* let's cut down on calls to time() */ + + /*************************** + * End of Global Variables * + ***************************/ + + /*********************** + * MCCP support * + ***********************/ + + extern const unsigned char compress_will[]; + extern const unsigned char compress_will2[]; + + #define TELOPT_COMPRESS 85 + #define TELOPT_COMPRESS2 86 + #define COMPRESS_BUF_SIZE 8192 + + /*********************** + * End of MCCP support * + ***********************/ + + /*********************************** + * Prototype function declerations * + ***********************************/ + + /* more compact */ + #define D_S D_SOCKET + #define D_M D_MOBILE + + #define buffer_new(size) __buffer_new ( size) + #define buffer_strcat(buffer,text) __buffer_strcat ( buffer, text ) + + char *crypt ( const char *key, const char *salt ); + + /* + * socket.c + */ + int init_socket ( void ); + bool new_socket ( int sock ); + void close_socket ( D_S *dsock, bool reconnect ); + bool read_from_socket ( D_S *dsock ); + bool text_to_socket ( D_S *dsock, const char *txt ); /* sends the output directly */ + void text_to_buffer ( D_S *dsock, const char *txt ); /* buffers the output */ + void text_to_mobile ( D_M *dMob, const char *txt ); /* buffers the output */ + void next_cmd_from_buffer ( D_S *dsock ); + bool flush_output ( D_S *dsock ); + void handle_new_connections ( D_S *dsock, char *arg ); + void clear_socket ( D_S *sock_new, int sock ); + void recycle_sockets ( void ); + void *lookup_address ( void *arg ); + + /* + * interpret.c + */ + void handle_cmd_input ( D_S *dsock, char *arg ); + + /* + * io.c + */ + void log_string ( const char *txt, ... ); + void bug ( const char *txt, ... ); + time_t last_modified ( char *helpfile ); + char *read_help_entry ( const char *helpfile ); /* pointer */ + char *fread_line ( FILE *fp ); /* pointer */ + char *fread_string ( FILE *fp ); /* allocated data */ + char *fread_word ( FILE *fp ); /* pointer */ + int fread_number ( FILE *fp ); /* just an integer */ + + /* + * strings.c + */ + char *one_arg ( char *fStr, char *bStr ); + bool compares ( const char *aStr, const char *bStr ); + bool is_prefix ( const char *aStr, const char *bStr ); + char *capitalize ( char *txt ); + BUFFER *__buffer_new ( int size ); + void __buffer_strcat ( BUFFER *buffer, const char *text ); + void buffer_free ( BUFFER *buffer ); + void buffer_clear ( BUFFER *buffer ); + int bprintf ( BUFFER *buffer, char *fmt, ... ); + + /* + * update.c + */ + void update_handler ( void ); + + /* + * help.c + */ + bool check_help ( D_M *dMob, char *helpfile ); + void load_helps ( void ); + void add_help ( HELP_DATA *help ); + + /* + * utils.c + */ + bool check_name ( const char *name ); + void clear_mobile ( D_M *dMob ); + void free_mobile ( D_M *dMob ); + void ex_free_mob ( D_MOBILE * dMob ); + void communicate ( D_M *dMob, char *txt, int range ); + void load_muddata ( bool fCopyOver ); + char *get_time ( void ); + void copyover_recover ( void ); + D_M *check_reconnect ( char *player ); + + /* + * action_safe.c + */ + void cmd_say ( D_M *dMob, char *arg ); + void cmd_quit ( D_M *dMob, char *arg ); + void cmd_shutdown ( D_M *dMob, char *arg ); + void cmd_commands ( D_M *dMob, char *arg ); + void cmd_who ( D_M *dMob, char *arg ); + void cmd_help ( D_M *dMob, char *arg ); + void cmd_compress ( D_M *dMob, char *arg ); + void cmd_save ( D_M *dMob, char *arg ); + void cmd_copyover ( D_M *dMob, char *arg ); + void cmd_linkdead ( D_M *dMob, char *arg ); + + /* + * mccp.c + */ + bool compressStart ( D_S *dsock, unsigned char teleopt ); + bool compressEnd ( D_S *dsock, unsigned char teleopt, bool forced ); + + /* + * save.c + */ + void save_player ( D_M *dMob ); + D_M *load_player ( char *player ); + D_M *load_profile ( char *player ); + + /******************************* + * End of prototype declartion * + *******************************/ + + #endif /* MUD_H */ diff -r -N -c socketmud/src/socket.c socketmud-event/src/socket.c *** socketmud/src/socket.c Thu Oct 2 13:07:32 2003 --- socketmud-event/src/socket.c Thu Oct 2 13:07:51 2003 *************** *** 54,59 **** --- 54,62 ---- /* note that we are booting up */ log_string("Program starting."); + /* initialize the event queue - part 1*/ + init_event_queue(1); + if (argv[1] && argv[1][0]) { fCopyOver = TRUE; *************** *** 68,73 **** --- 71,79 ---- /* load all external data */ load_muddata(fCopyOver); + /* initialize the event queue - part 2*/ + init_event_queue(2); + /* main game loop */ game_loop(control); *************** *** 181,188 **** close_socket(dsock, FALSE); } ! /* call the top-level update handler */ ! update_handler(); /* * Here we sleep out the rest of the pulse, thus forcing --- 187,194 ---- close_socket(dsock, FALSE); } ! /* call the event queue */ ! heartbeat(); /* * Here we sleep out the rest of the pulse, thus forcing *************** *** 354,359 **** --- 360,368 ---- text_to_buffer(sock_new, greeting); text_to_buffer(sock_new, "What is your name? "); + /* initialize socket events */ + init_events_socket(sock_new); + /* everything went as it was supposed to */ return TRUE; } *************** *** 386,391 **** --- 395,404 ---- else if (dsock->player) free_mobile(dsock->player); + /* dequeue all events for this socket */ + while (dsock->event_first) + dequeue_event(dsock->event_first); + /* set the closed state */ dsock->state = STATE_CLOSED; } *************** *** 945,950 **** --- 958,969 ---- /* and into the game */ dsock->state = STATE_PLAYING; text_to_buffer(dsock, motd); + + /* initialize events on the player */ + init_events_player(dsock->player); + + /* strip the idle event from this socket */ + strip_event_socket(dsock, EVENT_SOCKET_IDLE); } else { *************** *** 994,999 **** --- 1013,1024 ---- /* and let him enter the game */ dsock->state = STATE_PLAYING; text_to_buffer(dsock, motd); + + /* initialize events on the player */ + init_events_player(dsock->player); + + /* strip the idle event from this socket */ + strip_event_socket(dsock, EVENT_SOCKET_IDLE); } } else *************** *** 1017,1022 **** --- 1042,1049 ---- sock_new->lookup_status = TSTATE_LOOKUP; sock_new->player = NULL; sock_new->top_output = 0; + sock_new->event_first = NULL; + sock_new->event_last = NULL; } /* does the lookup, changes the hostname, and dies */ diff -r -N -c socketmud/src/update.c socketmud-event/src/update.c *** socketmud/src/update.c Thu Oct 2 13:07:32 2003 --- socketmud-event/src/update.c Thu Jan 1 01:00:00 1970 *************** *** 1,25 **** - /* - * This file contains all the update functions. - */ - #include - #include - - /* include main header file */ - #include "mud.h" - - /* - * Update_handler() - * - * This is the toplevel update function, - * which is called once every second. - */ - void update_handler() - { - D_SOCKET *dsock; - - for (dsock = dsock_list; dsock; dsock = dsock->next) - { - /* do nothing */ - } - return; - } --- 0 ---- diff -r -N -c socketmud/src/utils.c socketmud-event/src/utils.c *** socketmud/src/utils.c Thu Oct 2 13:07:32 2003 --- socketmud-event/src/utils.c Thu Oct 2 13:07:51 2003 *************** *** 38,43 **** --- 38,45 ---- dMob->name = NULL; dMob->password = NULL; dMob->level = LEVEL_PLAYER; + dMob->event_first = NULL; + dMob->event_last = NULL; } void free_mobile(D_MOBILE *dMob) *************** *** 75,80 **** --- 77,86 ---- free(dMob->name); free(dMob->password); + /* dequeue all events for this mobile */ + while (dMob->event_first) + dequeue_event(dMob->event_first); + /* put it back in the free list */ dMob->next = dmobile_free; dmobile_free = dMob; *************** *** 182,187 **** --- 188,196 ---- /* attach to mobile list */ dMob->next = dmobile_list; dmobile_list = dMob; + + /* initialize events on the player */ + init_events_player(dMob); } else /* ah bugger */ {