diff -dBbH --exclude-from=vanilla/diff_ignore --exclude-from=vanilla/.cvsignore --exclude Freeciv.h --exclude aaa.h --exclude 'rcstart*' --exclude 'short*' --exclude='civgame*.sav.gz' --exclude='*log*' --exclude=bb.out --exclude=aclocal.m4 --exclude='gmon*' --exclude='*.tgz' --exclude='*diff*' --exclude='*.rej' --exclude='.#*' --exclude=.deps --exclude=POTFILES --exclude=stamp-h --exclude='config*' --exclude=undep.sh --exclude='*.o' --exclude='*.orig' --exclude='*~' --exclude=Makefile --exclude=Makefile.in --exclude=CVS -pNur vanilla/README.compress_network compress/README.compress_network --- vanilla/README.compress_network Thu Jan 1 01:00:00 1970 +++ compress/README.compress_network Mon Nov 4 14:13:59 2002 @@ -0,0 +1,127 @@ +Version 0.3 + + Added per connection compression hint, triggered by +PACKET_PROCESSING_{STARTED,FINISHED}. This doesnt work for players with +shared vision, giving the old bad compression ratio to them, which shouldnt +be much of a problem, as those packets depend usually on player input so +they are not a big chunk of data. + + Changed global compression hint stop from send_year_to_clients to +send_start_turn_to_clients. If AI'ed this gives better compression. + + Included the old caching code I had around, including better packet stats. +Added short game info packets. + + Features are all controlled by defines in connection.h (and a debug CRC +on short city packets by a define in packets.c, but this is secondary). + + + Caching: +o Motivation: There is no need to send a city name 200 times during a game. +o Client and server initiate a cache of the information to the + same values (usually 0, this might be optimized (player index)). +o A new packet type is defined (PACKET_SHORT_X, instead of PACKET_X). This + includes a fixed header, which is made of the cache index and the flags. +o TX: check the cache to see if there is an entry. For all packet + values if the values in the cache and packet are different + set the flag for that value and update the cache. If the flag + is set, include the field in the packet. + If there were no changes, dont send the packet (happens apparently + for all cities on turn update, and sometimes for other packets). +o RX: Get the cache index out of the packet. Check the flag for a field, if + it's set, get the value off the packet and update the cache otherwise use + the cached value. +o The packet passed up to the upper layers is of kind PACKET_X, so this + caching is basically transparent to the rest of the code. + +Possible optimization: pass the flags to the upper layers, so precise +information about what has changed is known and work can be saved. + + +This has been implemented for following packet types, only in s->c +direction. The data is: the sizes for a random game on localhost (290000 +packets sent total) for comparison (normal avg size, short avg size, short +packet count), the cache index field and a short commentary: + +UNIT_INFO +. index id + +CITY_INFO (but not SHORT_CITY) +. index id + +TILE_INFO +. index x/y +. Small win per packet, but these get sent all too often. + +PLAYER_INFO +. index playerno +. If the timeout was not hit (non-AI game): sent 2*nplayers times, nplayers + times of them on update. + +GAME_INFO +. no index needed. +. at least once per turn, on turn update. And everytime you buy something. + + How to get an almost meaningful comparison: load a big game (many cities, many +units, big map). Connect 2 clients, one vanilla, the other with short packets, +to the same nation (one of them observing). AI the nation, let it fight some +other nation some time. + To get the size of a single update: same clients and server as above. Stop +the server (Ctrl-z or gdb), press turn done, stop both clients (vanilla and +compressing), reactivate server, 'netstat -tanp'. Reactivate both clients. + + The packet stats include avg bandwidth, this is mostly useless. A more useful +subjective metric is the time to get a full update. More precisely, the upper +bound on update time before you start hitting the wall with your head. +This is a subjective and game development dependent metric, 5 seconds might +not matter at peace, 2 seconds might be too long when at war. Hence the +importance of reducing PLAYER_INFO and GAME_INFO packets' size. + +This patch tries to slow down getting to that wall-head interaction point. + +FYI, my modem usually gets around 4kbytes/second. The wall is dented. + + My comments on particular program behaviour are based on a few games +on localhost. Maybe I got some part wrong. + + The patch modifies packets_lsend.c, the generating perl script should be modified. + +Version 0.2 + + Bug fixed: uncompressing clients dont get compression (I was checking the +server capabilities, not the clients' ). + + Hook in on the turn activities, so the compression state needs not be +flushed on every packet, which gives better compression efficiency. This +change compresses the bulk of the transmission problem, turn updates. Those +can easily get over 40kbytes, which can be at least 5 seconds on a modem +line. + + It may be a better idea to hook in in conn_list_do_unbuffer, but I dont +know the code enough to know if it would be 'right'. + +Causes of lag: +. Reconnect to a new game ( handle_request_join_game() ). +. Turn done update ( between before_end_year() and send_year_to_clients() ) +. Start of game (in srv_main(), around send_rulesets) + +Version 0.1 + + + It only compresses server->client. It could be easily extended to compress +c->s but I guess it isnt really worth the effort. + + The game_join packet effectively marks the last uncompressed packet. + + Some packets get a bad compression, gettting bigger. But those are usually +smaller packets. On average the stream gets effectively compressed. + + I guess it still is worth the effort to compress on lines < 128k and analog +modems with hardware compression. This reduces the numbers of packets, which +is good, letting the hardware compression concentrate on other recuring +patterns, like packet headers (OTOH I dont know how the hw compression +works, so take that statement with a bit of salt). + + It is not configurable, so for good links you are wasting CPU cycles. + +yon diff -dBbH --exclude-from=vanilla/diff_ignore --exclude-from=vanilla/.cvsignore --exclude Freeciv.h --exclude aaa.h --exclude 'rcstart*' --exclude 'short*' --exclude='civgame*.sav.gz' --exclude='*log*' --exclude=bb.out --exclude=aclocal.m4 --exclude='gmon*' --exclude='*.tgz' --exclude='*diff*' --exclude='*.rej' --exclude='.#*' --exclude=.deps --exclude=POTFILES --exclude=stamp-h --exclude='config*' --exclude=undep.sh --exclude='*.o' --exclude='*.orig' --exclude='*~' --exclude=Makefile --exclude=Makefile.in --exclude=CVS -pNur vanilla/client/civclient.c compress/client/civclient.c --- vanilla/client/civclient.c Wed Oct 9 15:39:47 2002 +++ compress/client/civclient.c Sun Nov 3 16:42:43 2002 @@ -259,6 +259,9 @@ void handle_packet_input(void *packet, i handle_new_year((struct packet_new_year *)packet); break; +#ifdef CONFIG_SUI_PACKETS + case PACKET_SHORT_UNIT_INFO: +#endif case PACKET_UNIT_INFO: handle_unit_info((struct packet_unit_info *)packet); break; @@ -267,6 +270,9 @@ void handle_packet_input(void *packet, i handle_move_unit(); break; +#ifdef CONFIG_STI_PACKETS + case PACKET_SHORT_TILE_INFO: +#endif case PACKET_TILE_INFO: handle_tile_info((struct packet_tile_info *)packet); break; @@ -275,10 +281,16 @@ void handle_packet_input(void *packet, i handle_select_nation((struct packet_nations_used *)packet); break; +#ifdef CONFIG_SPI_PACKETS + case PACKET_SHORT_PLAYER_INFO: +#endif case PACKET_PLAYER_INFO: handle_player_info((struct packet_player_info *)packet); break; +#ifdef CONFIG_SGI_PACKETS + case PACKET_SHORT_GAME_INFO: +#endif case PACKET_GAME_INFO: handle_game_info((struct packet_game_info *)packet); break; @@ -295,6 +307,9 @@ void handle_packet_input(void *packet, i handle_page_msg((struct packet_generic_message *)packet); break; +#ifdef CONFIG_SCI_PACKETS + case PACKET_SHORT_CITY_INFO: +#endif case PACKET_CITY_INFO: handle_city_info((struct packet_city_info *)packet); break; @@ -457,7 +473,8 @@ void handle_packet_input(void *packet, i break; default: - freelog(LOG_ERROR, "Received unknown packet (type %d) from server!", type); + freelog(LOG_ERROR, "Received unknown packet (type %d/%s) from server!", type, + (type < PACKET_LAST && packet_names[type] != NULL) ? packet_names[type] : ""); /* Old clients (<= some 1.11.5-devel, capstr +1.11) used to exit() * here, so server should not rely on client surviving. */ diff -dBbH --exclude-from=vanilla/diff_ignore --exclude-from=vanilla/.cvsignore --exclude Freeciv.h --exclude aaa.h --exclude 'rcstart*' --exclude 'short*' --exclude='civgame*.sav.gz' --exclude='*log*' --exclude=bb.out --exclude=aclocal.m4 --exclude='gmon*' --exclude='*.tgz' --exclude='*diff*' --exclude='*.rej' --exclude='.#*' --exclude=.deps --exclude=POTFILES --exclude=stamp-h --exclude='config*' --exclude=undep.sh --exclude='*.o' --exclude='*.orig' --exclude='*~' --exclude=Makefile --exclude=Makefile.in --exclude=CVS -pNur vanilla/client/clinet.c compress/client/clinet.c --- vanilla/client/clinet.c Tue Sep 17 15:09:47 2002 +++ compress/client/clinet.c Sat Oct 26 15:50:01 2002 @@ -77,6 +77,11 @@ #include "clinet.h" +#ifdef CONFIG_COMPRESSED_NETWORK +/* not used in the client, yet. But needs to be defined. */ +bool need_not_flush_compression = FALSE; +#endif + struct connection aconnection; static struct sockaddr_in server_addr; @@ -93,6 +98,11 @@ static void close_socket_nomessage(struc /* make sure not to use these accidently: */ free_socket_packet_buffer(pc->buffer); free_socket_packet_buffer(pc->send_buffer); +#ifdef CONFIG_COMPRESSED_NETWORK + free_socket_packet_buffer(pc->compress_tmp_rx_buffer); + pc->compress_tmp_rx_buffer = NULL; +/* XXX */ +#endif pc->buffer = NULL; pc->send_buffer = NULL; @@ -103,6 +113,50 @@ static void close_socket_nomessage(struc set_client_state(CLIENT_PRE_GAME_STATE); agents_disconnect(); + +#ifdef CONFIG_SPI_PACKETS + memset(&pc->pinfo_cache, 0, sizeof(pc->pinfo_cache) ); + pc->use_spi = FALSE; +#endif + +#ifdef CONFIG_STI_PACKETS + if(pc->map_cache) + { + free(pc->map_cache); + pc->map_cache = NULL; + } + pc->use_sti = FALSE; +#endif + +#ifdef CONFIG_SCI_PACKETS + if(pc->city_cache ) + { + // struct city_cache_entry* cce; + while (hash_num_entries(pc->city_cache) > 0) + free( hash_delete_entry(pc->city_cache, hash_key_by_number(pc->city_cache, 0)) ); + } + pc->use_sci = FALSE; +#endif + +#ifdef CONFIG_SUI_PACKETS + if(pc->unit_cache ) + { + while (hash_num_entries(pc->unit_cache) > 0) + free( hash_delete_entry(pc->unit_cache, hash_key_by_number(pc->unit_cache, 0)) ); + } + pc->use_sui = FALSE; +#endif + +#ifdef CONFIG_SGI_PACKETS + if(pc->game_info_cache ) { + freelog(LOG_ERROR, "Destroying game info cache "); + free(pc->game_info_cache); + pc->use_sgi = FALSE; + pc->game_info_cache = NULL; + } +#endif + + } /************************************************************************** @@ -195,10 +249,29 @@ int try_to_connect(char *user_name, char aconnection.buffer = NULL; free_socket_packet_buffer(aconnection.send_buffer); aconnection.send_buffer = NULL; +#ifdef CONFIG_COMPRESSED_NETWORK + free_socket_packet_buffer(aconnection.compress_tmp_rx_buffer); + aconnection.compress_tmp_rx_buffer = NULL; +#endif } +#ifdef CONFIG_COMPRESSED_NETWORK + if ( aconnection.compress_rx_ctx ) { + inflateEnd( aconnection.compress_rx_ctx ); + free( aconnection.compress_rx_ctx ); + aconnection.compress_rx_ctx = NULL ; + } + if ( aconnection.compress_tx_ctx ) { + deflateEnd( aconnection.compress_tx_ctx ); + free( aconnection.compress_tx_ctx ); + aconnection.compress_tx_ctx = NULL ; + } +#endif aconnection.buffer = new_socket_packet_buffer(); aconnection.send_buffer = new_socket_packet_buffer(); +#ifdef CONFIG_COMPRESSED_NETWORK + aconnection.compress_tmp_rx_buffer = new_socket_packet_buffer(); +#endif aconnection.last_write = 0; aconnection.client.last_request_id_used = 0; aconnection.client.last_processed_request_id_seen = 0; @@ -301,7 +374,11 @@ static int read_from_connection(struct c } if (FD_ISSET(socket_fd, &readfs)) { - return read_socket_data(socket_fd, pc->buffer); +#ifdef CONFIG_COMPRESSED_NETWORK + return read_socket_data_compressed(pc); +#else + return read_socket_data(pc->sock,pc->buffer); +#endif } } } diff -dBbH --exclude-from=vanilla/diff_ignore --exclude-from=vanilla/.cvsignore --exclude Freeciv.h --exclude aaa.h --exclude 'rcstart*' --exclude 'short*' --exclude='civgame*.sav.gz' --exclude='*log*' --exclude=bb.out --exclude=aclocal.m4 --exclude='gmon*' --exclude='*.tgz' --exclude='*diff*' --exclude='*.rej' --exclude='.#*' --exclude=.deps --exclude=POTFILES --exclude=stamp-h --exclude='config*' --exclude=undep.sh --exclude='*.o' --exclude='*.orig' --exclude='*~' --exclude=Makefile --exclude=Makefile.in --exclude=CVS -pNur vanilla/client/gui-gtk/diplodlg.c compress/client/gui-gtk/diplodlg.c --- vanilla/client/gui-gtk/diplodlg.c Wed Jun 12 09:24:34 2002 +++ compress/client/gui-gtk/diplodlg.c Wed Oct 16 16:42:41 2002 @@ -479,7 +479,7 @@ static struct Diplomacy_dialog *create_d pdialog->dip_labelm=gtk_label_new(buf); gtk_box_pack_start(GTK_BOX(pdialog->dip_vboxm), - pdialog->dip_labelm, TRUE, FALSE, 2); + pdialog->dip_labelm, FALSE, FALSE, 2); pdialog->dip_clauselist = gtk_clist_new_with_titles(1, titles); @@ -489,13 +489,13 @@ static struct Diplomacy_dialog *create_d gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC ); - gtk_widget_set_usize(scrolled, 350, 90); + // gtk_widget_set_usize(scrolled, 350, 90); gtk_box_pack_start(GTK_BOX(pdialog->dip_vboxm), - scrolled, TRUE, FALSE, 2); - + scrolled, TRUE, TRUE, 2); + /* YYY */ table=gtk_table_new(1,4,FALSE); - gtk_box_pack_start(GTK_BOX(pdialog->dip_vboxm), table, TRUE, FALSE, 2); + gtk_box_pack_start(GTK_BOX(pdialog->dip_vboxm), table, FALSE, FALSE, 2); my_snprintf(buf, sizeof(buf), _("%s view:"), get_nation_name(plr0->nation)); label=gtk_label_new(buf); @@ -517,16 +517,16 @@ static struct Diplomacy_dialog *create_d pdialog->dip_erase_clause_command=gtk_button_new_with_label(_("Erase clause")); gtk_box_pack_start(GTK_BOX(pdialog->dip_vboxm), - pdialog->dip_erase_clause_command, TRUE, FALSE, 2 ); + pdialog->dip_erase_clause_command, FALSE, FALSE, 2 ); pdialog->dip_accept_command=gtk_button_new_with_label(_("Accept treaty")); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(pdialog->dip_dialog_shell)->action_area), - pdialog->dip_accept_command, TRUE, TRUE, 2 ); + pdialog->dip_accept_command, FALSE, FALSE, 2 ); pdialog->dip_close_command=gtk_button_new_with_label(_("Cancel meeting")); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(pdialog->dip_dialog_shell)->action_area), - pdialog->dip_close_command, TRUE, TRUE, 2 ); + pdialog->dip_close_command, FALSE, FALSE, 2 ); gtk_signal_connect(GTK_OBJECT(pdialog->dip_close_command), "clicked", GTK_SIGNAL_FUNC(diplomacy_dialog_close_callback), pdialog); @@ -819,6 +819,9 @@ static void diplomacy_dialog_accept_call *****************************************************************/ void close_diplomacy_dialog(struct Diplomacy_dialog *pdialog) { + GtkRequisition req; + gtk_widget_get_child_requisition(pdialog->dip_dialog_shell, &req ); + printf("req: %d, %d\n", req.width, req.height); gtk_widget_destroy(pdialog->dip_dialog_shell); genlist_unlink(&diplomacy_dialogs, pdialog); diff -dBbH --exclude-from=vanilla/diff_ignore --exclude-from=vanilla/.cvsignore --exclude Freeciv.h --exclude aaa.h --exclude 'rcstart*' --exclude 'short*' --exclude='civgame*.sav.gz' --exclude='*log*' --exclude=bb.out --exclude=aclocal.m4 --exclude='gmon*' --exclude='*.tgz' --exclude='*diff*' --exclude='*.rej' --exclude='.#*' --exclude=.deps --exclude=POTFILES --exclude=stamp-h --exclude='config*' --exclude=undep.sh --exclude='*.o' --exclude='*.orig' --exclude='*~' --exclude=Makefile --exclude=Makefile.in --exclude=CVS -pNur vanilla/client/packhand.c compress/client/packhand.c --- vanilla/client/packhand.c Tue Sep 24 00:47:09 2002 +++ compress/client/packhand.c Sun Nov 3 11:41:11 2002 @@ -66,6 +66,10 @@ #include "agents.h" #include "audio.h" +#if defined(CONFIG_SCI_PACKETS) || defined(CONFIG_SUI_PACKETS) +#include "hash.h" +#endif + #include "packhand.h" static void handle_city_packet_common(struct city *pcity, bool is_new, @@ -134,6 +138,103 @@ void handle_join_game_reply(struct packe freelog(LOG_NORMAL, "%s", msg); } } +#ifdef CONFIG_SCI_PACKETS + if ( has_capability("packet_sci", packet->capability)) { + freelog(LOG_NORMAL, "Client accepting SCI packets."); + aconnection.use_sci = TRUE; + if(aconnection.city_cache == NULL) + aconnection.city_cache = hash_new_nentries(&hash_fval_keyval,&hash_fcmp_keyval,311) ; + } +#endif + +#ifdef CONFIG_SUI_PACKETS + if ( has_capability("packet_sui", packet->capability)) { + freelog(LOG_NORMAL, "Client accepting SUI packets."); + aconnection.use_sui = TRUE; + if(aconnection.unit_cache == NULL) + aconnection.unit_cache = hash_new_nentries(&hash_fval_keyval,&hash_fcmp_keyval,911) ; + } +#endif + +#ifdef CONFIG_SPI_PACKETS + if ( has_capability("packet_spi", packet->capability)) { + freelog(LOG_NORMAL, "Client accepting SPI packets."); + memset(&aconnection.pinfo_cache,0, sizeof(aconnection.pinfo_cache)); + aconnection.use_spi = TRUE; + } +#endif + +#ifdef CONFIG_STI_PACKETS + if ( has_capability("packet_sti", packet->capability)) { + freelog(LOG_NORMAL, "Client accepting STI packets."); + aconnection.use_sti = TRUE; + /* Map size is unknown yet */ + if( aconnection.map_cache != NULL ) + free(aconnection.map_cache); + } +#endif + +#ifdef CONFIG_SGI_PACKETS + if ( has_capability("packet_sgi", packet->capability)) { + freelog(LOG_NORMAL, "Client accepting SGI packets."); + aconnection.use_sgi = TRUE; + aconnection.game_info_cache = fc_malloc(sizeof(struct packet_game_info) ); + memset(aconnection.game_info_cache, 0, sizeof(struct packet_game_info)); + } +#endif + +#ifdef CONFIG_COMPRESSED_NETWORK + /* if server has compressed network capability, all communications + after this packet will be compressed, + BUT there may be a PACKET_PROCESSING_FINISHED packet still in the buffer. + I dont get what that is for. Someday I'll read the rest of the code --yon +*/ + if ( has_capability("compressed_network", packet->capability)) { + freelog(LOG_NORMAL, "Compression on."); + aconnection.compress_rx_ctx = fc_malloc( sizeof(struct z_stream_s)); + aconnection.compress_rx_ctx->zalloc = Z_NULL; + aconnection.compress_rx_ctx->zfree = Z_NULL; + aconnection.compress_rx_ctx->opaque = NULL; + inflateInit(aconnection.compress_rx_ctx); + + if ( aconnection.buffer->ndata > 2 + && aconnection.buffer->data[0] == 0 + && aconnection.buffer->data[1] == 3 + && aconnection.buffer->data[2] == PACKET_PROCESSING_FINISHED) { + aconnection.buffer->ndata -= 3; + if ( aconnection.buffer->ndata ) + memcpy(aconnection.buffer->data, + aconnection.buffer->data + 3, + aconnection.buffer->ndata ); + handle_processing_finished(); + } + + if ( aconnection.buffer->ndata > 0 ) { + /* compressed data in the uncompressed data buffer, move it around */ + memcpy(aconnection.compress_tmp_rx_buffer->data, + aconnection.buffer->data , aconnection.buffer->ndata); + aconnection.compress_tmp_rx_buffer->ndata = + aconnection.buffer->ndata; + /* and then uncompress it into the uncompressed data buffer */ + aconnection.compress_rx_ctx->avail_in = + aconnection.compress_tmp_rx_buffer->ndata; + aconnection.compress_rx_ctx->next_in = + aconnection.compress_tmp_rx_buffer->data; + aconnection.compress_rx_ctx->avail_out = aconnection.buffer->nsize; + aconnection.compress_rx_ctx->next_out = aconnection.buffer->data; + inflate( aconnection.compress_rx_ctx, Z_SYNC_FLUSH); +/* YYY extensive error checking */ +/* assert( 0 < aconnection.buffer->nsize - + aconnection.compress_rx_ctx->avail_out );*/ + assert( aconnection.compress_tmp_rx_buffer->ndata == + aconnection.compress_rx_ctx->total_in ); + aconnection.buffer->ndata= aconnection.compress_rx_ctx->total_out; + aconnection.compress_tmp_rx_buffer->ndata = 0; +/* aconnection.compress_rx_ctx->total_in; */ + } + } else + freelog(LOG_NORMAL, "Compression OFF."); +#endif if (strcmp(s_capability, our_capability) == 0) { return; } @@ -1030,6 +1131,17 @@ void handle_map_info(struct packet_map_i map.ysize=pinfo->ysize; map.is_earth=pinfo->is_earth; +#ifdef CONFIG_STI_PACKETS + if ( aconnection.use_sti == TRUE ) + if( aconnection.map_cache == NULL ) + { /* first use, allocate map buffer, size is known now */ + aconnection.map_cache = fc_malloc( map.xsize * map.ysize * + sizeof(struct map_cache_entry)); + memset( aconnection.map_cache, 0, map.xsize * map.ysize * + sizeof(struct map_cache_entry)); + } +#endif + map_allocate(); climap_init_continents(); init_client_goto(); @@ -1281,6 +1393,7 @@ void handle_conn_info(struct packet_conn pconn = fc_calloc(1, sizeof(struct connection)); pconn->buffer = NULL; pconn->send_buffer = NULL; + /* YYY */ if (pplayer) { conn_list_insert_back(&pplayer->connections, pconn); } diff -dBbH --exclude-from=vanilla/diff_ignore --exclude-from=vanilla/.cvsignore --exclude Freeciv.h --exclude aaa.h --exclude 'rcstart*' --exclude 'short*' --exclude='civgame*.sav.gz' --exclude='*log*' --exclude=bb.out --exclude=aclocal.m4 --exclude='gmon*' --exclude='*.tgz' --exclude='*diff*' --exclude='*.rej' --exclude='.#*' --exclude=.deps --exclude=POTFILES --exclude=stamp-h --exclude='config*' --exclude=undep.sh --exclude='*.o' --exclude='*.orig' --exclude='*~' --exclude=Makefile --exclude=Makefile.in --exclude=CVS -pNur vanilla/common/capstr.c compress/common/capstr.c --- vanilla/common/capstr.c Mon Oct 7 19:26:21 2002 +++ compress/common/capstr.c Tue Oct 22 18:53:54 2002 @@ -11,6 +11,10 @@ GNU General Public License for more details. ***********************************************************************/ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include /* getenv() */ @@ -69,8 +73,41 @@ const char * const our_capability = our_ * and checked by the same has_capability function, but the strings there * are not directly related to the capability strings discussed here.) */ +#ifdef CONFIG_COMPRESSED_NETWORK +#define CAP_COMPRESS " compressed_network" +#else +#define CAP_COMPRESS "" +#endif +#ifdef CONFIG_SPI_PACKETS +#define CAP_SPI " packet_spi" +#else +#define CAP_SPI "" +#endif +#ifdef CONFIG_STI_PACKETS +#define CAP_STI " packet_sti" +#else +#define CAP_STI "" +#endif +#ifdef CONFIG_SCI_PACKETS +#define CAP_SCI " packet_sci" +#else +#define CAP_SCI "" +#endif +#ifdef CONFIG_SUI_PACKETS +#define CAP_SUI " packet_sui" +#else +#define CAP_SUI "" +#endif +#ifdef CONFIG_SGI_PACKETS +#define CAP_SGI " packet_sgi" +#else +#define CAP_SGI "" +#endif -#define CAPABILITY "+1.14.0 conn_info" + + +#define CAPABILITY "+1.14.0 conn_info" \ +CAP_COMPRESS CAP_SPI CAP_STI CAP_SCI CAP_SUI CAP_SGI /* "+1.14.0" is protocol for 1.14.0 release. diff -dBbH --exclude-from=vanilla/diff_ignore --exclude-from=vanilla/.cvsignore --exclude Freeciv.h --exclude aaa.h --exclude 'rcstart*' --exclude 'short*' --exclude='civgame*.sav.gz' --exclude='*log*' --exclude=bb.out --exclude=aclocal.m4 --exclude='gmon*' --exclude='*.tgz' --exclude='*diff*' --exclude='*.rej' --exclude='.#*' --exclude=.deps --exclude=POTFILES --exclude=stamp-h --exclude='config*' --exclude=undep.sh --exclude='*.o' --exclude='*.orig' --exclude='*~' --exclude=Makefile --exclude=Makefile.in --exclude=CVS -pNur vanilla/common/city.c compress/common/city.c --- vanilla/common/city.c Thu Oct 17 10:35:32 2002 +++ compress/common/city.c Mon Oct 21 22:50:38 2002 @@ -72,21 +72,8 @@ struct citystyle *city_styles = NULL; /* from server/unittools.h */ void send_unit_info(struct player *dest, struct unit *punit); -/************************************************************************** -... -**************************************************************************/ -bool is_valid_city_coords(const int city_x, const int city_y) -{ - if ((city_x == 0 || city_x == CITY_MAP_SIZE-1) - && (city_y == 0 || city_y == CITY_MAP_SIZE-1)) - return FALSE; - if (city_x < 0 || city_y < 0 - || city_x >= CITY_MAP_SIZE - || city_y >= CITY_MAP_SIZE) - return FALSE; - - return TRUE; -} +/* from client/civclient.c or server/srv_main.c */ +extern bool is_server; /************************************************************************** ... diff -dBbH --exclude-from=vanilla/diff_ignore --exclude-from=vanilla/.cvsignore --exclude Freeciv.h --exclude aaa.h --exclude 'rcstart*' --exclude 'short*' --exclude='civgame*.sav.gz' --exclude='*log*' --exclude=bb.out --exclude=aclocal.m4 --exclude='gmon*' --exclude='*.tgz' --exclude='*diff*' --exclude='*.rej' --exclude='.#*' --exclude=.deps --exclude=POTFILES --exclude=stamp-h --exclude='config*' --exclude=undep.sh --exclude='*.o' --exclude='*.orig' --exclude='*~' --exclude=Makefile --exclude=Makefile.in --exclude=CVS -pNur vanilla/common/city.h compress/common/city.h --- vanilla/common/city.h Fri Sep 6 21:14:14 2002 +++ compress/common/city.h Fri Oct 18 05:31:51 2002 @@ -370,7 +370,22 @@ int get_food_tile(int x, int y); /* f /* city map functions */ -bool is_valid_city_coords(const int city_x, const int city_y); +/************************************************************************** +... +**************************************************************************/ +static inline bool is_valid_city_coords(const int city_x, const int city_y) +{ + if ((city_x == 0 || city_x == CITY_MAP_SIZE-1) + && (city_y == 0 || city_y == CITY_MAP_SIZE-1)) + return FALSE; + if (city_x < 0 || city_y < 0 + || city_x >= CITY_MAP_SIZE + || city_y >= CITY_MAP_SIZE) + return FALSE; + + return TRUE; +} + bool is_city_center(int city_x, int city_y); bool base_map_to_city_map(int *city_map_x, int *city_map_y, int city_center_x, int city_center_y, int map_x, diff -dBbH --exclude-from=vanilla/diff_ignore --exclude-from=vanilla/.cvsignore --exclude Freeciv.h --exclude aaa.h --exclude 'rcstart*' --exclude 'short*' --exclude='civgame*.sav.gz' --exclude='*log*' --exclude=bb.out --exclude=aclocal.m4 --exclude='gmon*' --exclude='*.tgz' --exclude='*diff*' --exclude='*.rej' --exclude='.#*' --exclude=.deps --exclude=POTFILES --exclude=stamp-h --exclude='config*' --exclude=undep.sh --exclude='*.o' --exclude='*.orig' --exclude='*~' --exclude=Makefile --exclude=Makefile.in --exclude=CVS -pNur vanilla/common/connection.c compress/common/connection.c --- vanilla/common/connection.c Wed Aug 7 13:21:45 2002 +++ compress/common/connection.c Thu Oct 31 10:24:27 2002 @@ -153,6 +153,79 @@ int read_socket_data(int sock, struct so return -1; } +#ifdef CONFIG_COMPRESSED_NETWORK +/* read_socket_data could be folded into this function */ + +/************************************************************************** + Read data from socket, and check if a packet is ready. + Returns: + -1 : an error occured - you should close the socket + >0 : number of bytes read + =0 : non-blocking sockets only; no data read, would block +**************************************************************************/ +int read_socket_data_compressed(struct connection *pc) +{ + int didget,didget2; + struct socket_packet_buffer *buffer; + if ( NULL != pc->compress_rx_ctx ) + buffer = pc->compress_tmp_rx_buffer; + else + buffer = pc->buffer; + + didget=my_readsocket(pc->sock, (char *)(buffer->data+buffer->ndata), + MAX_LEN_PACKET-buffer->ndata); +/* XXX? Why try to read only MAX_LEN_PACKET? buffer->nsize is 10 times as much. + Shouldnt it be (buffer->nsize - buffer->ndata )? + --yon +*/ + if (didget > 0) { + buffer->ndata+= didget; + + freelog(LOG_NORMAL, "didget:%d", didget); + if ( NULL != pc->compress_rx_ctx ) { + int dres, old_avail; + /* now decompress this */ + pc->compress_rx_ctx->avail_in = buffer->ndata; + pc->compress_rx_ctx->next_in = buffer->data; + old_avail = + pc->compress_rx_ctx->avail_out = + pc->buffer->nsize - pc->buffer->ndata; + pc->compress_rx_ctx->next_out = pc->buffer->data + pc->buffer->ndata; + dres = inflate( pc->compress_rx_ctx, Z_SYNC_FLUSH); + if ( dres != Z_OK && dres != Z_STREAM_END ) + assert(0); +/* YYY extensive error checking */ + didget2 = old_avail - pc->compress_rx_ctx->avail_out; + freelog(LOG_NORMAL, "didget2:%d,\t (%d%%)\t(%d%%)\t%d\t%d", didget2, + 100*didget/didget2, + (int)(100*pc->compress_rx_ctx->total_in/ + pc->compress_rx_ctx->total_out), + (int)pc->compress_rx_ctx->total_in, + (int)pc->compress_rx_ctx->total_out ); + assert( didget2 > 0 ); + didget = buffer->ndata - pc->compress_rx_ctx->avail_in; + pc->buffer->ndata+= didget2; + memmove(buffer->data, buffer->data + buffer->ndata - + pc->compress_rx_ctx->avail_in, + pc->compress_rx_ctx->avail_in); + buffer->ndata = pc->compress_rx_ctx->avail_in; + } + return didget; + } + else if (didget == 0) { + freelog(LOG_DEBUG, "EOF on socket read"); + return -1; + } +#ifdef NONBLOCKING_SOCKETS + else if (errno == EWOULDBLOCK || errno == EAGAIN) { + freelog(LOG_DEBUG, "EGAIN on socket read"); + return 0; + } +#endif + + return -1; +} +#endif /* CONFIG_COMPRESSED_NETWORK */ /************************************************************************** write wrapper function -vasc **************************************************************************/ @@ -262,7 +335,7 @@ void flush_connection_send_buffer_packet /************************************************************************** ... **************************************************************************/ -static bool add_connection_data(struct connection *pc, +bool add_connection_data(struct connection *pc, const unsigned char *data, int len) { if (pc && pc->delayed_disconnect) { diff -dBbH --exclude-from=vanilla/diff_ignore --exclude-from=vanilla/.cvsignore --exclude Freeciv.h --exclude aaa.h --exclude 'rcstart*' --exclude 'short*' --exclude='civgame*.sav.gz' --exclude='*log*' --exclude=bb.out --exclude=aclocal.m4 --exclude='gmon*' --exclude='*.tgz' --exclude='*diff*' --exclude='*.rej' --exclude='.#*' --exclude=.deps --exclude=POTFILES --exclude=stamp-h --exclude='config*' --exclude=undep.sh --exclude='*.o' --exclude='*.orig' --exclude='*~' --exclude=Makefile --exclude=Makefile.in --exclude=CVS -pNur vanilla/common/connection.h compress/common/connection.h --- vanilla/common/connection.h Wed Aug 7 13:21:45 2002 +++ compress/common/connection.h Sun Nov 3 17:13:31 2002 @@ -23,8 +23,19 @@ Includes cmdlevel stuff, which is connection-based. ***************************************************************************/ -#include "shared.h" /* MAX_LEN_ADDR */ -#include "shared.h" /* bool type */ +#include "shared.h" /* MAX_LEN_ADDR and bool type */ + +#ifdef HAVE_LIBZ +#if 1 +#define CONFIG_COMPRESSED_NETWORK 1 +#endif +#endif + +#ifdef CONFIG_COMPRESSED_NETWORK +#include "zlib.h" +/* compression hint, srv_main.c and clinet.c */ +extern bool need_not_flush_compression; +#endif struct player; @@ -32,6 +43,22 @@ struct player; #define MAX_LEN_CAPSTR 512 #define MAX_LEN_BUFFER (MAX_LEN_PACKET * 128) +#if 1 +#define CONFIG_SPI_PACKETS +#endif +#if 1 +#define CONFIG_SCI_PACKETS +#endif +#if 1 +#define CONFIG_STI_PACKETS +#endif +#if 1 +#define CONFIG_SUI_PACKETS +#endif +#if 1 +#define CONFIG_SGI_PACKETS +#endif + /************************************************************************** Command access levels for client-side use; at present, they are only used to control access to server commands typed at the client chatline. @@ -61,6 +88,9 @@ struct connection; #define SPECLIST_TAG conn #define SPECLIST_TYPE struct connection #include "speclist.h" +#include "worklist.h" +#include "tech.h" +#include "city.h" #define conn_list_iterate(connlist, pconn) \ TYPED_LIST_ITERATE(struct connection, connlist, pconn) @@ -76,6 +106,140 @@ struct socket_packet_buffer { int nsize; unsigned char *data; }; +#ifdef CONFIG_SPI_PACKETS +/*************************************************************************** +... +***************************************************************************/ +struct pinfo_cache_entry { + int pnumber; + char name [MAX_LEN_NAME]; + int embassy; + int reputation; + int gold; + int nturns_idle; + int government; + int city_style; + int nation; + int combined; + int tax, science, luxury; + int researching; + int future_tech, tech_goal; + int bulbs_researched, techs_researched; + int gives_shared_vision; + /* int number_inventions; */ + int barbarian_type; + unsigned char inventions[A_LAST]; + struct worklist worklists[MAX_NUM_WORKLISTS]; + struct { + unsigned char combined; + unsigned short turns_left; + } diplstates[MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS]; +}; +#endif + +#ifdef CONFIG_STI_PACKETS +/*************************************************************************** +... +***************************************************************************/ +struct map_cache_entry { + unsigned char x,y; + unsigned char type; /* enum 14 values: 4bits */ + unsigned short special; /* enum 14bits */ + unsigned char known; /* 2 bits */ +}; +#endif + +#ifdef CONFIG_SCI_PACKETS +/*************************************************************************** +... +***************************************************************************/ +#if 1 +struct city_cache_entry { + struct city_cache_entry *next; /* linked list in hash table */ + int hash_value; + int id; + int owner,x,y; + char name[MAX_LEN_NAME]; + int size; + int ppl_angry[5],ppl_happy[5],ppl_unhappy[5], ppl_content[5]; + int ppl_elvis,ppl_scientist,ppl_taxman; + int food_prod,food_surplus; + int shield_prod, shield_surplus; + int trade_prod, tile_trade; + int corruption; + int luxury_total,tax_total,science_total; + int food_stock, shield_stock, pollution; + int currently_building; + int turn_last_built, turn_changed_target; + int changed_from_id ; + int before_change_shields; + int disbanded_shields, caravan_shields; + struct worklist worklist; + int flags1 ; + char city_map[CITY_MAP_SIZE*CITY_MAP_SIZE+1]; + char improvements[B_LAST+1]; + int city_options; + int trade[4]; + int trade_value[4]; + int turn_founded; +}; +#else +/* int* is evil */ +/*************************************************************************** +... +***************************************************************************/ +struct city_cache_entry { + struct city_cache_entry *next; /* linked list in hash table */ + int hash_value; + unsigned short id; + unsigned char owner,x,y; + char name[MAX_LEN_NAME]; + unsigned char size; + /*unsigned char*/ int ppl_angry[5],ppl_happy[5],ppl_unhappy[5], ppl_content[5]; + unsigned char ppl_elvis,ppl_scientist,ppl_taxman; + unsigned char food_prod,food_surplus; + unsigned short shield_prod, shield_surplus; + unsigned short trade_prod, tile_trade; + unsigned short corruption; + unsigned short luxury_total,tax_total,science_total; + unsigned short food_stock, shield_stock, pollution; + unsigned char currently_building; + short turn_last_built, turn_changed_target; + unsigned char changed_from_id ; + unsigned short before_change_shields; + unsigned short disbanded_shields, caravan_shields; + struct worklist worklist; + unsigned char flags1 ; + unsigned char city_map[CITY_MAP_SIZE*CITY_MAP_SIZE+1]; + unsigned char improvements[B_LAST+1]; + unsigned char city_options; + unsigned short trade[4]; + unsigned char trade_value[4]; + unsigned short turn_founded; +}; +#endif +#endif + +#ifdef CONFIG_SUI_PACKETS +/*************************************************************************** +... +***************************************************************************/ +struct unit_cache_entry { + struct unit_cache_entry *next; // linked list in hash table + int hash_value; + unsigned short id; + unsigned char owner,x,y; + unsigned char pack; + unsigned short homecity; + unsigned char type, movesleft, hp, upkeep, upkeep_food, upkeep_gold; + unsigned char unhappiness, activity, activity_count; + unsigned char goto_dest_x, goto_dest_y; + unsigned short activity_target; + unsigned char packet_use; + unsigned short info_city_id, serial_num; + unsigned short fuel; +}; +#endif /*********************************************************** The connection struct represents a single client or server @@ -93,6 +257,26 @@ struct connection { bool observer; /* connection is "observer", not controller; may be observing specific player, or all (implementation incomplete) */ +#ifdef CONFIG_SPI_PACKETS + struct pinfo_cache_entry pinfo_cache[MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS]; + bool use_spi; /* gets calculated once per connection */ +#endif +#ifdef CONFIG_STI_PACKETS + struct map_cache_entry *map_cache; + bool use_sti; /* gets calculated once per connection */ +#endif +#ifdef CONFIG_SCI_PACKETS + bool use_sci; /* gets calculated once per connection */ + struct hash_table *city_cache; +#endif +#ifdef CONFIG_SUI_PACKETS + struct hash_table *unit_cache; + bool use_sui; /* gets calculated once per connection */ +#endif +#ifdef CONFIG_SGI_PACKETS + bool use_sgi; /* gets calculated once per connection */ + struct packet_game_info *game_info_cache; +#endif struct socket_packet_buffer *buffer; struct socket_packet_buffer *send_buffer; time_t last_write; @@ -117,6 +301,16 @@ struct connection { bool delayed_disconnect; /* Something has occured that means the connection should be closed, but the closing has been postponed. */ +#ifdef CONFIG_COMPRESSED_NETWORK + /* 0 flush + 1 not flush + 2 flush with next packet and set to 0 + */ + int need_not_flush_compression; + struct z_stream_s *compress_rx_ctx; + struct z_stream_s *compress_tx_ctx; + struct socket_packet_buffer *compress_tmp_rx_buffer; +#endif void (*notify_of_writable_data) (struct connection * pc, bool data_available_and_socket_full); @@ -178,6 +372,12 @@ typedef void (*CLOSE_FUN) (struct connec void close_socket_set_callback(CLOSE_FUN fun); int read_socket_data(int sock, struct socket_packet_buffer *buffer); +#ifdef CONFIG_COMPRESSED_NETWORK +int read_socket_data_compressed(struct connection *pc); +/* need to export this */ +extern bool add_connection_data(struct connection *pc, + const unsigned char *data, int len); +#endif void flush_connection_send_buffer_all(struct connection *pc); void flush_connection_send_buffer_packets(struct connection *pc); void send_connection_data(struct connection *pc, const unsigned char *data, diff -dBbH --exclude-from=vanilla/diff_ignore --exclude-from=vanilla/.cvsignore --exclude Freeciv.h --exclude aaa.h --exclude 'rcstart*' --exclude 'short*' --exclude='civgame*.sav.gz' --exclude='*log*' --exclude=bb.out --exclude=aclocal.m4 --exclude='gmon*' --exclude='*.tgz' --exclude='*diff*' --exclude='*.rej' --exclude='.#*' --exclude=.deps --exclude=POTFILES --exclude=stamp-h --exclude='config*' --exclude=undep.sh --exclude='*.o' --exclude='*.orig' --exclude='*~' --exclude=Makefile --exclude=Makefile.in --exclude=CVS -pNur vanilla/common/dataio.c compress/common/dataio.c --- vanilla/common/dataio.c Wed Oct 9 15:31:09 2002 +++ compress/common/dataio.c Thu Oct 17 14:58:26 2002 @@ -114,20 +114,6 @@ void dio_set_get_conv_callback(DIO_GET_C get_conv_callback = fun; } -/************************************************************************** - Returns TRUE iff the output has size bytes available. -**************************************************************************/ -static bool enough_space(struct data_out *dout, size_t size) -{ - if (ADD_TO_POINTER(dout->current, size) >= - ADD_TO_POINTER(dout->dest, dout->dest_size)) { - dout->too_short = TRUE; - return FALSE; - } else { - dout->used = MAX(dout->used, dout->current + size); - return TRUE; - } -} /************************************************************************** Returns TRUE iff the input contains size unread bytes. @@ -207,6 +193,7 @@ size_t dio_input_remaining(struct data_i /************************************************************************** ... **************************************************************************/ +/* void dio_put_uint8(struct data_out *dout, int value) { if (enough_space(dout, 1)) { @@ -216,7 +203,7 @@ void dio_put_uint8(struct data_out *dout dout->current++; } } - +*/ /************************************************************************** ... **************************************************************************/ diff -dBbH --exclude-from=vanilla/diff_ignore --exclude-from=vanilla/.cvsignore --exclude Freeciv.h --exclude aaa.h --exclude 'rcstart*' --exclude 'short*' --exclude='civgame*.sav.gz' --exclude='*log*' --exclude=bb.out --exclude=aclocal.m4 --exclude='gmon*' --exclude='*.tgz' --exclude='*diff*' --exclude='*.rej' --exclude='.#*' --exclude=.deps --exclude=POTFILES --exclude=stamp-h --exclude='config*' --exclude=undep.sh --exclude='*.o' --exclude='*.orig' --exclude='*~' --exclude=Makefile --exclude=Makefile.in --exclude=CVS -pNur vanilla/common/dataio.h compress/common/dataio.h --- vanilla/common/dataio.h Thu Sep 19 16:39:37 2002 +++ compress/common/dataio.h Thu Oct 17 14:59:55 2002 @@ -77,8 +77,32 @@ void dio_get_uint16_vec8(struct data_in #define DIO_BV_GET(pdin, bv) \ dio_get_memory((pdin), (bv).vec, sizeof((bv).vec)) +/************************************************************************** + Returns TRUE iff the output has size bytes available. +**************************************************************************/ +static inline bool enough_space(struct data_out *dout, size_t size) +{ + if (ADD_TO_POINTER(dout->current, size) >= + ADD_TO_POINTER(dout->dest, dout->dest_size)) { + dout->too_short = TRUE; + return FALSE; + } else { + dout->used = MAX(dout->used, dout->current + size); + return TRUE; + } +} + + /* puts */ -void dio_put_uint8(struct data_out *dout, int value); +static inline void dio_put_uint8(struct data_out *dout, int value){ + if (enough_space(dout, 1)) { + unsigned char x = value; + + memcpy(ADD_TO_POINTER(dout->dest, dout->current), &x, 1); + dout->current++; + } +} + void dio_put_uint16(struct data_out *dout, int value); void dio_put_uint32(struct data_out *dout, int value); diff -dBbH --exclude-from=vanilla/diff_ignore --exclude-from=vanilla/.cvsignore --exclude Freeciv.h --exclude aaa.h --exclude 'rcstart*' --exclude 'short*' --exclude='civgame*.sav.gz' --exclude='*log*' --exclude=bb.out --exclude=aclocal.m4 --exclude='gmon*' --exclude='*.tgz' --exclude='*diff*' --exclude='*.rej' --exclude='.#*' --exclude=.deps --exclude=POTFILES --exclude=stamp-h --exclude='config*' --exclude=undep.sh --exclude='*.o' --exclude='*.orig' --exclude='*~' --exclude=Makefile --exclude=Makefile.in --exclude=CVS -pNur vanilla/common/genlist.c compress/common/genlist.c --- vanilla/common/genlist.c Sat Feb 16 18:05:06 2002 +++ compress/common/genlist.c Fri Oct 18 03:07:15 2002 @@ -161,48 +161,7 @@ void genlist_insert(struct genlist *pgen pgenlist->nelements++; } -/************************************************************************ - Initialize a genlist_iterator, for specified genlist and position - of initial element. If pos is out of range the link will be null_link - (which will generally be interpreted as the iterator being finished). - Recall 'pos' can be -1 meaning the last element. -************************************************************************/ -void genlist_iterator_init(struct genlist_iterator *iter, - struct genlist *pgenlist, int pos) -{ - iter->list=pgenlist; - iter->link=find_genlist_position(pgenlist, pos); -} - -/************************************************************************ - Returns a pointer to the genlist link structure at the specified - position. Recall 'pos' -1 refers to the last position. - For pos out of range returns the null_link. - Traverses list either forwards or backwards for best efficiency. -************************************************************************/ -struct genlist_link * -find_genlist_position(struct genlist *pgenlist, int pos) -{ - struct genlist_link *plink; - - if(pos==0) - return pgenlist->head_link; - else if(pos==-1) - return pgenlist->tail_link; - else if(pos<-1 || pos>=pgenlist->nelements) - return &pgenlist->null_link; - - if(posnelements/2) /* fastest to do forward search */ - for(plink=pgenlist->head_link; pos != 0; pos--) - plink=plink->next; - - else /* fastest to do backward search */ - for(plink=pgenlist->tail_link,pos=pgenlist->nelements-pos-1; pos != 0; pos--) - plink=plink->prev; - - return plink; -} /************************************************************************ diff -dBbH --exclude-from=vanilla/diff_ignore --exclude-from=vanilla/.cvsignore --exclude Freeciv.h --exclude aaa.h --exclude 'rcstart*' --exclude 'short*' --exclude='civgame*.sav.gz' --exclude='*log*' --exclude=bb.out --exclude=aclocal.m4 --exclude='gmon*' --exclude='*.tgz' --exclude='*diff*' --exclude='*.rej' --exclude='.#*' --exclude=.deps --exclude=POTFILES --exclude=stamp-h --exclude='config*' --exclude=undep.sh --exclude='*.o' --exclude='*.orig' --exclude='*~' --exclude=Makefile --exclude=Makefile.in --exclude=CVS -pNur vanilla/common/genlist.h compress/common/genlist.h --- vanilla/common/genlist.h Mon Feb 11 11:38:02 2002 +++ compress/common/genlist.h Fri Oct 18 03:06:50 2002 @@ -100,15 +100,54 @@ void *genlist_get(struct genlist *pgenli void genlist_init(struct genlist *pgenlist); void genlist_unlink_all(struct genlist *pgenlist); void genlist_insert(struct genlist *pgenlist, void *data, int pos); -struct genlist_link * -find_genlist_position(struct genlist *pgenlist, int pos); + +/************************************************************************ + Returns a pointer to the genlist link structure at the specified + position. Recall 'pos' -1 refers to the last position. + For pos out of range returns the null_link. + Traverses list either forwards or backwards for best efficiency. +************************************************************************/ +static inline struct genlist_link * +find_genlist_position(struct genlist *pgenlist, int pos) +{ + struct genlist_link *plink; + + if(pos==0) + return pgenlist->head_link; + else if(pos==-1) + return pgenlist->tail_link; + else if(pos<-1 || pos>=pgenlist->nelements) + return &pgenlist->null_link; + + if(posnelements/2) /* fastest to do forward search */ + for(plink=pgenlist->head_link; pos != 0; pos--) + plink=plink->next; + + else /* fastest to do backward search */ + for(plink=pgenlist->tail_link,pos=pgenlist->nelements-pos-1; pos != 0; pos--) + plink=plink->prev; + + return plink; +} + + void genlist_unlink(struct genlist *pgenlist, void *punlink); void genlist_sort(struct genlist *pgenlist, int (*compar)(const void *, const void *)); -void genlist_iterator_init(struct genlist_iterator *iter, - struct genlist *pgenlist, int pos); +/************************************************************************ + Initialize a genlist_iterator, for specified genlist and position + of initial element. If pos is out of range the link will be null_link + (which will generally be interpreted as the iterator being finished). + Recall 'pos' can be -1 meaning the last element. +************************************************************************/ +static inline void genlist_iterator_init(struct genlist_iterator *iter, + struct genlist *pgenlist, int pos) +{ + iter->list=pgenlist; + iter->link=find_genlist_position(pgenlist, pos); +} #define ITERATOR_PTR(X) ((X).link->dataptr) #define ITERATOR_NEXT(X) ((X).link=(X).link->next) diff -dBbH --exclude-from=vanilla/diff_ignore --exclude-from=vanilla/.cvsignore --exclude Freeciv.h --exclude aaa.h --exclude 'rcstart*' --exclude 'short*' --exclude='civgame*.sav.gz' --exclude='*log*' --exclude=bb.out --exclude=aclocal.m4 --exclude='gmon*' --exclude='*.tgz' --exclude='*diff*' --exclude='*.rej' --exclude='.#*' --exclude=.deps --exclude=POTFILES --exclude=stamp-h --exclude='config*' --exclude=undep.sh --exclude='*.o' --exclude='*.orig' --exclude='*~' --exclude=Makefile --exclude=Makefile.in --exclude=CVS -pNur vanilla/common/improvement.c compress/common/improvement.c --- vanilla/common/improvement.c Sat Oct 19 06:02:07 2002 +++ compress/common/improvement.c Sat Oct 19 16:50:55 2002 @@ -231,58 +231,6 @@ void improvements_free() } impr_type_iterate_end; } -/************************************************************************** -Returns 1 if the improvement_type "exists" in this game, 0 otherwise. -An improvement_type doesn't exist if one of: -- id is out of range; -- the improvement_type has been flagged as removed by setting its - tech_req to A_LAST; -- it is a space part, and the spacerace is not enabled. -Arguably this should be called improvement_type_exists, but that's too long. -**************************************************************************/ -bool improvement_exists(Impr_Type_id id) -{ - if (id<0 || id>=B_LAST || id>=game.num_impr_types) - return FALSE; - - if ((id==B_SCOMP || id==B_SMODULE || id==B_SSTRUCTURAL) - && !game.spacerace) - return FALSE; - - return (improvement_types[id].tech_req!=A_LAST); -} - -/************************************************************************** -... -**************************************************************************/ -struct impr_type *get_improvement_type(Impr_Type_id id) -{ - return &improvement_types[id]; -} - -/************************************************************************** -... -**************************************************************************/ -const char *get_improvement_name(Impr_Type_id id) -{ - return get_improvement_type(id)->name; -} - -/************************************************************************** -... -**************************************************************************/ -int improvement_value(Impr_Type_id id) -{ - return (improvement_types[id].build_cost); -} - -/************************************************************************** -... -**************************************************************************/ -bool is_wonder(Impr_Type_id id) -{ - return (improvement_types[id].is_wonder); -} /************************************************************************** Does a linear search of improvement_types[].name @@ -350,6 +298,27 @@ static void fill_ranges_improv_lists(Imp implist[EFR_WORLD]=game.improvements; } +/************************************************************************** +Returns 1 if the improvement_type "exists" in this game, 0 otherwise. +An improvement_type doesn't exist if one of: +- id is out of range; +- the improvement_type has been flagged as removed by setting its + tech_req to A_LAST; +- it is a space part, and the spacerace is not enabled. +Arguably this should be called improvement_type_exists, but that's too long. +**************************************************************************/ +bool improvement_exists(Impr_Type_id id) +{ + if (id<0 || id>=B_LAST || id>=game.num_impr_types) + return FALSE; + + if ((id==B_SCOMP || id==B_SMODULE || id==B_SSTRUCTURAL) + && !game.spacerace) + return FALSE; + + return (improvement_types[id].tech_req!=A_LAST); +} + /************************************************************************** Checks whether the building is within the equiv_range of a building that diff -dBbH --exclude-from=vanilla/diff_ignore --exclude-from=vanilla/.cvsignore --exclude Freeciv.h --exclude aaa.h --exclude 'rcstart*' --exclude 'short*' --exclude='civgame*.sav.gz' --exclude='*log*' --exclude=bb.out --exclude=aclocal.m4 --exclude='gmon*' --exclude='*.tgz' --exclude='*diff*' --exclude='*.rej' --exclude='.#*' --exclude=.deps --exclude=POTFILES --exclude=stamp-h --exclude='config*' --exclude=undep.sh --exclude='*.o' --exclude='*.orig' --exclude='*~' --exclude=Makefile --exclude=Makefile.in --exclude=CVS -pNur vanilla/common/improvement.h compress/common/improvement.h --- vanilla/common/improvement.h Sat Oct 19 06:16:16 2002 +++ compress/common/improvement.h Mon Oct 21 22:57:10 2002 @@ -155,7 +155,11 @@ enum effect_type { EFT_LAST /* keep this last */ }; -/* An effect conferred by an improvement. */ +//typedef enum effect_type_id Eff_Type_id; + +/* An effect conferred by an improvement. + */ + struct impr_effect { enum effect_type type; enum effect_range range; @@ -253,15 +258,42 @@ struct eff_global *append_geff(struct ge /* improvement functions */ void improvement_free(Impr_Type_id id); void improvements_free(void); -struct impr_type *get_improvement_type(Impr_Type_id id); +//struct impr_type *get_improvement_type(Impr_Type_id id); bool improvement_exists(Impr_Type_id id); -int improvement_value(Impr_Type_id id); -bool is_wonder(Impr_Type_id id); -const char *get_improvement_name(Impr_Type_id id); +/************************************************************************** +... +**************************************************************************/ +static inline struct impr_type *get_improvement_type(Impr_Type_id id) +{ + return &improvement_types[id]; +} -/* FIXME: remove improvement_variant() when gen-impr obsoletes */ -int improvement_variant(Impr_Type_id id); +/************************************************************************** +... +**************************************************************************/ +static inline const char *get_improvement_name(Impr_Type_id id) +{ + return get_improvement_type(id)->name; +} +/************************************************************************** +... +**************************************************************************/ +static inline int improvement_value(Impr_Type_id id) +{ + return (improvement_types[id].build_cost); +} + +/************************************************************************** +... +**************************************************************************/ +static inline bool is_wonder(Impr_Type_id id) +{ + return (improvement_types[id].is_wonder); +} + + +int improvement_variant(Impr_Type_id id); /* FIXME: remove when gen-impr obsoletes */ bool improvement_obsolete(struct player *pplayer, Impr_Type_id id); bool improvement_redundant(struct player *pplayer,struct city *pcity, Impr_Type_id id, bool want_to_build); diff -dBbH --exclude-from=vanilla/diff_ignore --exclude-from=vanilla/.cvsignore --exclude Freeciv.h --exclude aaa.h --exclude 'rcstart*' --exclude 'short*' --exclude='civgame*.sav.gz' --exclude='*log*' --exclude=bb.out --exclude=aclocal.m4 --exclude='gmon*' --exclude='*.tgz' --exclude='*diff*' --exclude='*.rej' --exclude='.#*' --exclude=.deps --exclude=POTFILES --exclude=stamp-h --exclude='config*' --exclude=undep.sh --exclude='*.o' --exclude='*.orig' --exclude='*~' --exclude=Makefile --exclude=Makefile.in --exclude=CVS -pNur vanilla/common/map.c compress/common/map.c --- vanilla/common/map.c Thu Oct 17 10:35:32 2002 +++ compress/common/map.c Thu Oct 31 22:51:23 2002 @@ -65,7 +65,8 @@ static const char *tile_special_type_nam N_("Fallout") }; -#define MAP_TILE(x,y) (map.tiles + map_inx(x, y)) +extern bool is_server; + /*************************************************************** ... @@ -1156,21 +1158,6 @@ void tile_free(struct tile *ptile) unit_list_unlink_all(&ptile->units); } -/*************************************************************** -... -***************************************************************/ -struct tile *map_get_tile(int x, int y) -{ - return MAP_TILE(x, y); -} - -/*************************************************************** -... -***************************************************************/ -signed short map_get_continent(int x, int y) -{ - return MAP_TILE(x, y)->continent; -} /*************************************************************** ... @@ -1181,57 +1168,6 @@ void map_set_continent(int x, int y, int } -/*************************************************************** -... -***************************************************************/ -enum tile_terrain_type map_get_terrain(int x, int y) -{ - return MAP_TILE(x, y)->terrain; -} - -/*************************************************************** -... -***************************************************************/ -enum tile_special_type map_get_special(int x, int y) -{ - return MAP_TILE(x, y)->special; -} - -/*************************************************************** - Returns TRUE iff the given special is found at the given map - position. -***************************************************************/ -bool map_has_special(int x, int y, enum tile_special_type special) -{ - return contains_special(MAP_TILE(x, y)->special, special); -} - -/*************************************************************** - Returns TRUE iff the given tile has the given special. -***************************************************************/ -bool tile_has_special(struct tile *ptile, enum tile_special_type special) -{ - return contains_special(ptile->special, special); -} - -/*************************************************************** - Returns TRUE iff the given special is found in the given set. -***************************************************************/ -bool contains_special(enum tile_special_type set, - enum tile_special_type to_test_for) -{ - enum tile_special_type masked = set & to_test_for; - - assert(0 == (int) S_NO_SPECIAL); - - /* - * contains_special should only be called with one S_* in - * to_test_for. - */ - assert(masked == S_NO_SPECIAL || masked == to_test_for); - - return masked == to_test_for; -} /*************************************************************** ... @@ -1268,60 +1204,11 @@ void map_clear_special(int x, int y, enu /*************************************************************** ... ***************************************************************/ -struct city *map_get_city(int x, int y) -{ - return MAP_TILE(x, y)->city; -} - -/*************************************************************** -... -***************************************************************/ void map_set_city(int x, int y, struct city *pcity) { MAP_TILE(x, y)->city = pcity; } -/*************************************************************** - Are (x1,y1) and (x2,y2) really the same when adjusted? - This function might be necessary ALOT of places... -***************************************************************/ -bool same_pos(int x1, int y1, int x2, int y2) -{ - CHECK_MAP_POS(x1, y1); - CHECK_MAP_POS(x2, y2); - return (x1 == x2 && y1 == y2); -} - -bool is_real_tile(int x, int y) -{ - return normalize_map_pos(&x, &y); -} - -/************************************************************************** -Returns TRUE iff the map position is normal. "Normal" here means that -it is both a real/valid coordinate set and that the coordinates are in -their canonical/proper form. In plain English: the coordinates must be -on the map. -**************************************************************************/ -bool is_normal_map_pos(int x, int y) -{ - int x1 = x, y1 = y; - - return (normalize_map_pos(&x1, &y1) && (x1 == x) && (y1 == y)); -} - -/************************************************************************** -Normalizes the map position. Returns TRUE if it is real, FALSE otherwise. -**************************************************************************/ -bool normalize_map_pos(int *x, int *y) -{ - while (*x < 0) - *x += map.xsize; - while (*x >= map.xsize) - *x -= map.xsize; - - return (0 <= *y && *y < map.ysize); -} /************************************************************************** Twiddle *x and *y to point the the nearest real tile, and ensure that the diff -dBbH --exclude-from=vanilla/diff_ignore --exclude-from=vanilla/.cvsignore --exclude Freeciv.h --exclude aaa.h --exclude 'rcstart*' --exclude 'short*' --exclude='civgame*.sav.gz' --exclude='*log*' --exclude=bb.out --exclude=aclocal.m4 --exclude='gmon*' --exclude='*.tgz' --exclude='*diff*' --exclude='*.rej' --exclude='.#*' --exclude=.deps --exclude=POTFILES --exclude=stamp-h --exclude='config*' --exclude=undep.sh --exclude='*.o' --exclude='*.orig' --exclude='*~' --exclude=Makefile --exclude=Makefile.in --exclude=CVS -pNur vanilla/common/map.h compress/common/map.h --- vanilla/common/map.h Thu Oct 17 13:20:50 2002 +++ compress/common/map.h Sat Oct 19 16:50:56 2002 @@ -180,6 +180,31 @@ struct civ_map { struct map_position start_positions[MAX_NUM_NATIONS]; }; +extern struct civ_map map; + +#ifdef DEBUG +#define CHECK_MAP_POS(x,y) assert(is_normal_map_pos((x),(y))) +#else +#define CHECK_MAP_POS(x,y) ((void)0) +#endif + +#define map_inx(x,y) \ + (CHECK_MAP_POS((x),(y)), (x)+(y)*map.xsize) + +#define MAP_TILE(x,y) (map.tiles + map_inx(x, y)) + +/*************************************************************** + Are (x1,y1) and (x2,y2) really the same when adjusted? + This function might be necessary ALOT of places... +***************************************************************/ +static inline bool same_pos(int x1, int y1, int x2, int y2) +{ + CHECK_MAP_POS(x1, y1); + CHECK_MAP_POS(x2, y2); + return (x1 == x2 && y1 == y2); +} + + bool map_is_empty(void); void map_init(void); void map_allocate(void); @@ -187,27 +212,36 @@ void map_free(void); const char *map_get_tile_info_text(int x, int y); const char *map_get_tile_fpt_text(int x, int y); -struct tile *map_get_tile(int x, int y); + +/*************************************************************** +... +***************************************************************/ +static inline struct tile *map_get_tile(int x, int y) +{ + return MAP_TILE(x, y); +} int map_distance(int x0, int y0, int x1, int y1); int real_map_distance(int x0, int y0, int x1, int y1); int sq_map_distance(int x0, int y0, int x1, int y1); -bool same_pos(int x1, int y1, int x2, int y2); bool base_get_direction_for_step(int start_x, int start_y, int end_x, int end_y, int *dir); int get_direction_for_step(int start_x, int start_y, int end_x, int end_y); void map_set_continent(int x, int y, int val); -signed short map_get_continent(int x, int y); + +/*************************************************************** +... +***************************************************************/ +static inline signed short map_get_continent(int x, int y) +{ + return MAP_TILE(x, y)->continent; +} + void initialize_move_costs(void); void reset_move_costs(int x, int y); -#ifdef DEBUG -#define CHECK_MAP_POS(x,y) assert(is_normal_map_pos((x),(y))) -#else -#define CHECK_MAP_POS(x,y) ((void)0) -#endif #define map_adjust_x(X) \ ((X) < 0 \ @@ -219,8 +253,6 @@ void reset_move_costs(int x, int y); #define map_adjust_y(Y) \ (((Y)<0) ? 0 : (((Y)>=map.ysize) ? map.ysize-1 : (Y))) -#define map_inx(x,y) \ - (CHECK_MAP_POS((x),(y)), (x)+(y)*map.xsize) #define DIRSTEP(dest_x, dest_y, dir) \ ( (dest_x) = DIR_DX[(dir)], \ @@ -240,24 +272,75 @@ void reset_move_costs(int x, int y); (dest_y) = (src_y) + DIR_DY[(dir)], \ normalize_map_pos(&(dest_x), &(dest_y))) -struct city *map_get_city(int x, int y); +/*************************************************************** +... +***************************************************************/ +static inline struct city *map_get_city(int x, int y) +{ + return MAP_TILE(x, y)->city; +} + void map_set_city(int x, int y, struct city *pcity); -enum tile_terrain_type map_get_terrain(int x, int y); -enum tile_special_type map_get_special(int x, int y); + +/*************************************************************** +... +***************************************************************/ +static inline enum tile_terrain_type map_get_terrain(int x, int y) +{ + return MAP_TILE(x, y)->terrain; +} + +/*************************************************************** +... +***************************************************************/ +static inline enum tile_special_type map_get_special(int x, int y) +{ + return MAP_TILE(x, y)->special; +} + void map_set_terrain(int x, int y, enum tile_terrain_type ter); void map_set_special(int x, int y, enum tile_special_type spe); void map_clear_special(int x, int y, enum tile_special_type spe); void tile_init(struct tile *ptile); void tile_free(struct tile *ptile); -bool is_real_tile(int x, int y); -bool is_normal_map_pos(int x, int y); + +/*************************************************************** + Returns TRUE iff the given special is found in the given set. +***************************************************************/ +static inline bool contains_special(enum tile_special_type set, + enum tile_special_type to_test_for) +{ + enum tile_special_type masked = set & to_test_for; + + assert(0 == (int) S_NO_SPECIAL); + + /* + * contains_special should only be called with one S_* in + * to_test_for. + */ + assert(masked == S_NO_SPECIAL || masked == to_test_for); + + return masked == to_test_for; +} /* special testing */ -bool map_has_special(int x, int y, enum tile_special_type to_test_for); -bool tile_has_special(struct tile *ptile, - enum tile_special_type to_test_for); -bool contains_special(enum tile_special_type all, - enum tile_special_type to_test_for); +/*************************************************************** + Returns TRUE iff the given special is found at the given map + position. +***************************************************************/ +static inline bool map_has_special(int x, int y, enum tile_special_type special) +{ + return contains_special(MAP_TILE(x, y)->special, special); +} + +/*************************************************************** + Returns TRUE iff the given tile has the given special. +***************************************************************/ +static inline bool tile_has_special(struct tile *ptile, enum tile_special_type special) +{ + return contains_special(ptile->special, special); +} + /* * Determines whether the position is normal given that it's in the @@ -275,7 +358,38 @@ bool contains_special(enum tile_special_ ((x) < (dist) || (x) >= map.xsize - (dist) \ || (y) < (dist) || (y) >= map.ysize - (dist)) -bool normalize_map_pos(int *x, int *y); +/************************************************************************** +Normalizes the map position. Returns TRUE if it is real, FALSE otherwise. +**************************************************************************/ +static inline bool normalize_map_pos(int *x, int *y) +{ + while (*x < 0) + *x += map.xsize; + while (*x >= map.xsize) + *x -= map.xsize; + + return (0 <= *y && *y < map.ysize); +} +/************************************************************************** +Returns TRUE iff the map position is normal. "Normal" here means that +it is both a real/valid coordinate set and that the coordinates are in +their canonical/proper form. In plain English: the coordinates must be +on the map. +**************************************************************************/ +static inline bool is_normal_map_pos(int x, int y) +{ + int x1 = x, y1 = y; + + return (normalize_map_pos(&x1, &y1) && (x1 == x) && (y1 == y)); +} + + +static inline bool is_real_tile(int x, int y) +{ + return normalize_map_pos(&x, &y); +} + + void nearest_real_pos(int *x, int *y); void map_distance_vector(int *dx, int *dy, int x0, int y0, int x1, int y1); int map_num_tiles(void); @@ -333,7 +447,6 @@ int map_activity_time(enum unit_activity bool can_channel_land(int x, int y); bool can_reclaim_ocean(int x, int y); -extern struct civ_map map; extern struct terrain_misc terrain_control; extern struct tile_type tile_types[T_LAST]; diff -dBbH --exclude-from=vanilla/diff_ignore --exclude-from=vanilla/.cvsignore --exclude Freeciv.h --exclude aaa.h --exclude 'rcstart*' --exclude 'short*' --exclude='civgame*.sav.gz' --exclude='*log*' --exclude=bb.out --exclude=aclocal.m4 --exclude='gmon*' --exclude='*.tgz' --exclude='*diff*' --exclude='*.rej' --exclude='.#*' --exclude=.deps --exclude=POTFILES --exclude=stamp-h --exclude='config*' --exclude=undep.sh --exclude='*.o' --exclude='*.orig' --exclude='*~' --exclude=Makefile --exclude=Makefile.in --exclude=CVS -pNur vanilla/common/packets.c compress/common/packets.c --- vanilla/common/packets.c Mon Oct 28 18:40:13 2002 +++ compress/common/packets.c Mon Nov 4 13:20:29 2002 @@ -19,6 +19,8 @@ #include #include #include +#include +#include "hash.h" #ifdef HAVE_SYS_TYPES_H #include @@ -43,8 +45,22 @@ #include "packets.h" +#ifdef CONFIG_COMPRESSED_NETWORK +#include +#include "connection.h" +#endif + #define PACKET_SIZE_STATISTICS 0 +#ifdef HAVE_CONFIG_H +#ifdef HAVE_LIBZ +/* debugging help */ +#if 0 +#define CONFIG_SCI_PACKETS_CRC +#endif +#endif +#endif + /********************************************************************** The current packet functions don't handle signed values correct. This will probably lead to problems when compiling @@ -70,6 +86,11 @@ dio_put_uint16(&dout, 0); \ dio_put_uint8(&dout, type); +#define SEND_PACKET_ABORT \ + { /* not sure if this is right for the client part*/ \ + return 0; \ + } + #define SEND_PACKET_END \ { \ size_t size = dio_output_used(&dout); \ @@ -101,6 +122,130 @@ static int send_packet_data(struct connection *pc, unsigned char *data, int len); +#ifdef PACKET_SIZE_STATISTICS + +#define packet_name(X) [X] = #X + +char* packet_names[PACKET_LAST+1] = { + packet_name(PACKET_REQUEST_JOIN_GAME), + packet_name(PACKET_JOIN_GAME_REPLY), + packet_name(PACKET_PROCESSING_STARTED), + packet_name(PACKET_PROCESSING_FINISHED), + packet_name(PACKET_SERVER_SHUTDOWN), + packet_name(PACKET_UNIT_INFO), + packet_name(PACKET_MOVE_UNIT), + packet_name(PACKET_TURN_DONE), + packet_name(PACKET_NEW_YEAR), + packet_name(PACKET_TILE_INFO), + packet_name(PACKET_SELECT_NATION), + packet_name(PACKET_ALLOC_NATION), + packet_name(PACKET_SHOW_MESSAGE), + packet_name(PACKET_PLAYER_INFO), + packet_name(PACKET_GAME_INFO), + packet_name(PACKET_MAP_INFO), + packet_name(PACKET_CHAT_MSG), + packet_name(PACKET_CITY_INFO), + packet_name(PACKET_CITY_SELL), + packet_name(PACKET_CITY_BUY), + packet_name(PACKET_CITY_CHANGE), + packet_name(PACKET_CITY_WORKLIST), + packet_name(PACKET_CITY_MAKE_SPECIALIST), + packet_name(PACKET_CITY_MAKE_WORKER), + packet_name(PACKET_CITY_CHANGE_SPECIALIST), + packet_name(PACKET_CITY_RENAME), + packet_name(PACKET_PLAYER_RATES), + packet_name(PACKET_PLAYER_REVOLUTION), + packet_name(PACKET_PLAYER_GOVERNMENT), + packet_name(PACKET_PLAYER_RESEARCH), + packet_name(PACKET_UNIT_BUILD_CITY), + packet_name(PACKET_UNIT_DISBAND), + packet_name(PACKET_REMOVE_UNIT), + packet_name(PACKET_REMOVE_CITY), + packet_name(PACKET_UNIT_CHANGE_HOMECITY), + packet_name(PACKET_UNIT_COMBAT), + packet_name(PACKET_UNIT_ESTABLISH_TRADE), + packet_name(PACKET_UNIT_HELP_BUILD_WONDER), + packet_name(PACKET_UNIT_GOTO_TILE), + packet_name(PACKET_GAME_STATE), + packet_name(PACKET_NUKE_TILE), + packet_name(PACKET_DIPLOMAT_ACTION), + packet_name(PACKET_PAGE_MSG), + packet_name(PACKET_REPORT_REQUEST), + packet_name(PACKET_DIPLOMACY_INIT_MEETING), + packet_name(PACKET_DIPLOMACY_CREATE_CLAUSE), + packet_name(PACKET_DIPLOMACY_REMOVE_CLAUSE), + packet_name(PACKET_DIPLOMACY_CANCEL_MEETING), + packet_name(PACKET_DIPLOMACY_ACCEPT_TREATY), + packet_name(PACKET_DIPLOMACY_SIGN_TREATY), + packet_name(PACKET_UNIT_AUTO), + packet_name(PACKET_BEFORE_NEW_YEAR), + packet_name(PACKET_REMOVE_PLAYER), + packet_name(PACKET_UNITTYPE_UPGRADE), + packet_name(PACKET_UNIT_UNLOAD), + packet_name(PACKET_PLAYER_TECH_GOAL), + packet_name(PACKET_CITY_REFRESH), + packet_name(PACKET_INCITE_INQ), + packet_name(PACKET_INCITE_COST), + packet_name(PACKET_UNIT_UPGRADE), + packet_name(PACKET_PLAYER_CANCEL_PACT), + packet_name(PACKET_RULESET_TECH), + packet_name(PACKET_RULESET_UNIT), + packet_name(PACKET_RULESET_BUILDING), + packet_name(PACKET_CITY_OPTIONS), + packet_name(PACKET_SPACESHIP_INFO), + packet_name(PACKET_SPACESHIP_ACTION), + packet_name(PACKET_UNIT_NUKE), + packet_name(PACKET_RULESET_TERRAIN), + packet_name(PACKET_RULESET_TERRAIN_CONTROL), + packet_name(PACKET_RULESET_GOVERNMENT), + packet_name(PACKET_RULESET_GOVERNMENT_RULER_TITLE), + packet_name(PACKET_RULESET_CONTROL), + packet_name(PACKET_CITY_NAME_SUGGEST_REQ), + packet_name(PACKET_CITY_NAME_SUGGESTION), + packet_name(PACKET_RULESET_NATION), + packet_name(PACKET_UNIT_PARADROP_TO), + packet_name(PACKET_RULESET_CITY), + packet_name(PACKET_UNIT_CONNECT), + packet_name(PACKET_SABOTAGE_LIST), + packet_name(PACKET_ADVANCE_FOCUS), + packet_name(PACKET_RULESET_GAME), + packet_name(PACKET_CONN_INFO), + packet_name(PACKET_SHORT_CITY), + packet_name(PACKET_PLAYER_REMOVE_VISION), + packet_name(PACKET_GOTO_ROUTE), + packet_name(PACKET_PATROL_ROUTE), + packet_name(PACKET_CONN_PING), + packet_name(PACKET_CONN_PONG), + packet_name(PACKET_UNIT_AIRLIFT), + packet_name(PACKET_ATTRIBUTE_CHUNK), + packet_name(PACKET_PLAYER_ATTRIBUTE_BLOCK), + packet_name(PACKET_START_TURN), + packet_name(PACKET_SELECT_NATION_OK), + packet_name(PACKET_FREEZE_HINT), + packet_name(PACKET_THAW_HINT), +#ifdef CONFIG_COMPRESSED_NETWORK + packet_name(PACKET_START_COMPRESSION), +#endif +#ifdef CONFIG_SPI_PACKETS + packet_name(PACKET_SHORT_PLAYER_INFO), +#endif +#ifdef CONFIG_STI_PACKETS + packet_name(PACKET_SHORT_TILE_INFO), +#endif +#ifdef CONFIG_SCI_PACKETS + packet_name(PACKET_SHORT_CITY_INFO), +#endif +#ifdef CONFIG_SUI_PACKETS + packet_name(PACKET_SHORT_UNIT_INFO), +#endif +#ifdef CONFIG_SGI_PACKETS + packet_name(PACKET_SHORT_GAME_INFO), +#endif + packet_name(PACKET_LAST) /* leave this last */ +}; +#endif + + /************************************************************************** It returns the request id of the outgoing packet or 0 if the packet was no request (i.e. server sends packet). @@ -110,8 +255,16 @@ static int send_packet_data(struct conne { /* default for the server */ int result = 0; +#ifdef CONFIG_COMPRESSED_NETWORK + static char compressed[12+ (int)(10.02 * MAX_LEN_PACKET)]; + int clen, cres, flush = 0; +#endif - freelog(LOG_DEBUG, "sending packet type=%d len=%d", data[2], len); +#ifdef PACKET_SIZE_STATISTICS + freelog(LOG_ERROR, "sending packet %s len=%d", packet_names[data[2]], len); +#else + freelog(LOG_ERROR, "sending packet type=%d len=%d", data[2], len); +#endif if (!is_server) { pc->client.last_request_id_used = @@ -124,16 +277,19 @@ static int send_packet_data(struct conne pc->outgoing_packet_notify(pc, data[2], len, result); } -#if PACKET_SIZE_STATISTICS +#ifdef PACKET_SIZE_STATISTICS { static struct { int counter; int size; } packets_stats[PACKET_LAST]; static int packet_counter = 0; + static struct timeval start; + struct timeval now; int packet_type = data[2]; int size = len; + double microseconds; if (!packet_counter) { int i; @@ -142,6 +298,7 @@ static int send_packet_data(struct conne packets_stats[i].counter = 0; packets_stats[i].size = 0; } + gettimeofday( &start ,NULL); } packets_stats[packet_type].counter++; @@ -152,27 +309,81 @@ static int send_packet_data(struct conne || (is_server && (packet_counter % 1000 == 0))) { int i, sum = 0; - freelog(LOG_NORMAL, "Transmitted packets:"); + gettimeofday(&now, NULL); + microseconds = 1e6 * (double)( now.tv_sec - start.tv_sec ) + + (double)( now.tv_usec - start.tv_usec ); + freelog(LOG_ERROR, "Transmitted packets:"); for (i = 0; i < PACKET_LAST; i++) { if (packets_stats[i].counter == 0) continue; sum += packets_stats[i].size; - freelog(LOG_NORMAL, - " [%2d]: %6d packets; %8d bytes total; " - "%5d bytes/packet average", - i, packets_stats[i].counter, + freelog(LOG_ERROR, + " [%2d/%30s]: %6d packets; %8d bytes total; " + "%5d bytes/packet, bw %05.3f", + i, 7+packet_names[i],packets_stats[i].counter, packets_stats[i].size, - packets_stats[i].size / packets_stats[i].counter); + packets_stats[i].size / packets_stats[i].counter, + (8e3f * (float)packets_stats[i].size)/(float)microseconds); } - freelog(LOG_NORMAL, - "transmitted %d bytes in %d packets;average size " - "per packet %d bytes", - sum, packet_counter, sum / packet_counter); + freelog(LOG_ERROR, + "transmitted %d bytes in %d packets, %3.0f pps;average " + "per packet %d bytes, bw %05.3f, time %.3f", + sum, packet_counter, (float)packet_counter/(float)microseconds/1e6f, + sum / packet_counter, + (8e3f * (float)sum)/(float)microseconds, + (float)microseconds/1e6f); } } #endif +#ifdef CONFIG_COMPRESSED_NETWORK + if ( NULL != pc->compress_tx_ctx ) { + /* For some packet types there is no need to flush the compression state, + which degrades compression efficiency. + In fact, implementing a timeout would be a better solution, collecting + data and compressing and sending it when the timer expires. + I suggest 100ms for the timeout, in fact slightly equalizing lag. + --yon + */ +/* but NOT || pc->observer || + ( NULL != pc->player && FALSE == pc->player->is_alive) */ + if ( need_not_flush_compression + || 1 == pc->need_not_flush_compression) + flush = 0; + else + switch ( data[2] ) { + /* etc ... */ + case PACKET_LAST: + flush = 0; + default: + flush = Z_SYNC_FLUSH; + } + + pc->compress_tx_ctx->next_in = data; + pc->compress_tx_ctx->avail_in = len; + pc->compress_tx_ctx->next_out = compressed ; + pc->compress_tx_ctx->avail_out = sizeof(compressed); + compress_more: + cres = deflate(pc->compress_tx_ctx, flush); + if ( cres != Z_OK && cres != Z_STREAM_END ) + assert(0 && cres); + clen = sizeof(compressed) - pc->compress_tx_ctx->avail_out; + if ( pc->compress_tx_ctx->avail_in > 0) { + add_connection_data (pc, compressed, clen); + goto compress_more; + } + +/* NOT assert( pc->compress_tx_ctx->avail_in == 0); */ + send_connection_data(pc, compressed, clen); + + if ( pc->need_not_flush_compression == 2 ) + pc->need_not_flush_compression = 0; + } + else send_connection_data(pc, data, len); +#else + send_connection_data(pc, data, len); +#endif return result; } @@ -203,7 +414,11 @@ void *get_packet_from_connection(struct if(pc->first_packet) { /* the first packet better be short: */ - freelog(LOG_DEBUG, "first packet type %d len %d", type, len); +#ifdef PACKET_SIZE_STATISTICS + freelog(LOG_ERROR, "first packet type %s len %d", packet_names[type], len); +#else + freelog(LOG_ERROR, "first packet type %d len %d", type, len); +#endif pc->first_packet = FALSE; } @@ -211,7 +426,12 @@ void *get_packet_from_connection(struct return NULL; /* not all data has been read */ } - freelog(LOG_DEBUG, "got packet type=%d len=%d", type, len); +#ifdef PACKET_SIZE_STATISTICS + freelog(LOG_VERBOSE, "got packet type=%s len=%d buffer=%d", packet_names[type] + , len, pc->buffer->ndata); +#else + freelog(LOG_VERBOSE, "got packet type=%d len=%d", type, len); +#endif *ptype=type; *presult = TRUE; @@ -220,16 +440,19 @@ void *get_packet_from_connection(struct pc->incoming_packet_notify(pc, type, len); } -#if PACKET_SIZE_STATISTICS +#ifdef PACKET_SIZE_STATISTICS { static struct { int counter; int size; } packets_stats[PACKET_LAST]; static int packet_counter = 0; + static struct timeval start; + struct timeval now; int packet_type = type; int size = len; + long microseconds = 0; if (!packet_counter) { int i; @@ -238,6 +461,7 @@ void *get_packet_from_connection(struct packets_stats[i].counter = 0; packets_stats[i].size = 0; } + gettimeofday( &start ,NULL); } packets_stats[packet_type].counter++; @@ -248,28 +472,35 @@ void *get_packet_from_connection(struct || (!is_server && (packet_counter % 1000 == 0))) { int i, sum = 0; + gettimeofday(&now, NULL); + microseconds = 1e6L * ( now.tv_sec - start.tv_sec ) + + ( now.tv_usec - start.tv_usec ); freelog(LOG_NORMAL, "Received packets:"); for (i = 0; i < PACKET_LAST; i++) { if (packets_stats[i].counter == 0) continue; sum += packets_stats[i].size; - freelog(LOG_NORMAL, - " [%2d]: %6d packets; %8d bytes total; " - "%5d bytes/packet average", - i, packets_stats[i].counter, + freelog(LOG_ERROR, + " [%2d/%30s]: %6d packets; %8d bytes total; " + "%5d bytes/packet ,bw %05.3f", + i, 7+packet_names[i],packets_stats[i].counter, packets_stats[i].size, - packets_stats[i].size / packets_stats[i].counter); + packets_stats[i].size / packets_stats[i].counter, + (8e3f * (float)packets_stats[i].size)/(float)microseconds); } - freelog(LOG_NORMAL, - "received %d bytes in %d packets;average size " - "per packet %d bytes", - sum, packet_counter, sum / packet_counter); + freelog(LOG_ERROR, + "received %d bytes in %d packets, %3.0f pps;average " + "packet %d bytes, bw %.3f, time %.3f", + sum, packet_counter, (float)packet_counter/(float)microseconds/1e6f, + sum / packet_counter, + (8e3f*(float)sum)/(float)microseconds, + (float)microseconds/1e6f); } } #endif - switch(type) { + switch(type) { case PACKET_REQUEST_JOIN_GAME: return receive_packet_req_join_game(pc); @@ -282,9 +513,19 @@ void *get_packet_from_connection(struct case PACKET_UNIT_INFO: return receive_packet_unit_info(pc); +#ifdef CONFIG_SUI_PACKETS + case PACKET_SHORT_UNIT_INFO: + return receive_packet_short_unit_info(pc); +#endif + case PACKET_CITY_INFO: return receive_packet_city_info(pc); +#ifdef CONFIG_SCI_PACKETS + case PACKET_SHORT_CITY_INFO: + return receive_packet_short_city_info(pc); +#endif + case PACKET_SHORT_CITY: return receive_packet_short_city(pc); @@ -311,6 +552,11 @@ void *get_packet_from_connection(struct case PACKET_TILE_INFO: return receive_packet_tile_info(pc); +#ifdef CONFIG_STI_PACKETS + case PACKET_SHORT_TILE_INFO: + return receive_packet_short_tile_info(pc); +#endif + case PACKET_SELECT_NATION: return receive_packet_nations_used(pc); @@ -336,6 +582,16 @@ void *get_packet_from_connection(struct case PACKET_PLAYER_INFO: return receive_packet_player_info(pc); +#ifdef CONFIG_SPI_PACKETS + case PACKET_SHORT_PLAYER_INFO: + return receive_packet_short_player_info(pc); +#endif + +#ifdef CONFIG_SGI_PACKETS + case PACKET_SHORT_GAME_INFO: + return receive_packet_short_game_info(pc); +#endif + case PACKET_GAME_INFO: return receive_packet_game_info(pc); @@ -394,6 +650,7 @@ void *get_packet_from_connection(struct case PACKET_DIPLOMACY_ACCEPT_TREATY: case PACKET_DIPLOMACY_SIGN_TREATY: return receive_packet_diplomacy_info(pc); + break; case PACKET_INCITE_COST: case PACKET_CITY_OPTIONS: @@ -448,8 +705,14 @@ void *get_packet_from_connection(struct return receive_packet_attribute_chunk(pc); default: +#ifdef PACKET_SIZE_STATISTICS + freelog(LOG_ERROR, "unknown packet type %s received from %s", + (type < PACKET_LAST && packet_names[type] != NULL) ? packet_names[type] : "" , + conn_description(pc)); +#else freelog(LOG_ERROR, "unknown packet type %d received from %s", type, conn_description(pc)); +#endif remove_packet_from_buffer(pc->buffer); return NULL; }; @@ -500,14 +763,25 @@ static void check_packet(struct data_in } if (rem < 0) { +#ifdef PACKET_SIZE_STATISTICS + freelog(LOG_ERROR, "received short packet (type %s, len %d)%s", + packet_names[type], len, from); +#else freelog(LOG_ERROR, "received short packet (type %d, len %d)%s", type, len, from); +#endif } else if (rem > 0) { /* This may be ok, eg a packet from a newer version with extra info * which we should just ignore */ - freelog(LOG_VERBOSE, +#ifdef PACKET_SIZE_STATISTICS + freelog(LOG_ERROR, "received long packet (type %d/%s, len %d, rem %d)%s", + type, packet_names[type] != NULL ? + packet_names[type] : "",len, rem, from); +#else + freelog(LOG_ERROR, "received long packet (type %d, len %d, rem %lu)%s", type, len, (unsigned long)rem, from); +#endif } } } @@ -814,6 +1088,11 @@ int send_packet_player_info(struct conne int i; SEND_PACKET_START(PACKET_PLAYER_INFO); +#ifdef CONFIG_SPI_PACKETS + if ( is_server && pc->use_spi ) + return send_packet_short_player_info(pc, pinfo); +#endif + dio_put_uint8(&dout, pinfo->playerno); dio_put_string(&dout, pinfo->name); @@ -865,6 +1144,9 @@ struct packet_player_info *receive_packe { int i; RECEIVE_PACKET_START(packet_player_info, pinfo); +#ifdef CONFIG_SPI_PACKETS + assert( ! pc->use_spi ); +#endif dio_get_uint8(&din, &pinfo->playerno); dio_get_string(&din, pinfo->name, sizeof(pinfo->name)); @@ -973,6 +1255,11 @@ int send_packet_game_info(struct connect int i; SEND_PACKET_START(PACKET_GAME_INFO); +#ifdef CONFIG_SGI_PACKETS + if ( is_server && pc->use_sgi ) + return send_packet_short_game_info(pc, pinfo); +#endif + dio_put_uint16(&dout, pinfo->gold); dio_put_uint32(&dout, pinfo->tech); dio_put_uint8(&dout, pinfo->researchcost); @@ -1021,6 +1308,10 @@ struct packet_game_info *receive_packet_ int i; RECEIVE_PACKET_START(packet_game_info, pinfo); +#ifdef CONFIG_SGI_PACKETS + assert( ! pc->use_sgi ); +#endif + dio_get_uint16(&din, &pinfo->gold); dio_get_uint32(&din, &pinfo->tech); dio_get_uint8(&din, &pinfo->researchcost); @@ -1061,6 +1352,216 @@ struct packet_game_info *receive_packet_ RECEIVE_PACKET_END(pinfo); } +#ifdef CONFIG_SGI_PACKETS +struct packet_game_info *receive_packet_short_game_info(struct connection *pc) +{ + int flags, i; + RECEIVE_PACKET_START(packet_game_info, pinfo); + dio_get_uint32(&din, &flags); + + pinfo->angrycitizen = flags & FLGSGI_angrycitizen ? TRUE : FALSE; + pinfo->spacerace = flags & FLGSGI_spacerace ? TRUE : FALSE; + +#define sgi_r(size,m) \ + if ( flags & FLGSGI_##m ) \ + { \ + dio_get_uint##size(&din, &pinfo->m); \ + pc->game_info_cache->m = pinfo->m; \ + } \ + else \ + { \ + pinfo->m = pc->game_info_cache->m; \ + } + +#define sgi_rs(size,m) \ + if ( flags & FLGSGI_##m ) \ + { \ + dio_get_sint##size(&din, &pinfo->m); \ + pc->game_info_cache->m = pinfo->m; \ + } \ + else \ + { \ + pinfo->m = pc->game_info_cache->m; \ + } + + sgi_r(32, gold); + sgi_r(32, tech); + sgi_r(8, researchcost); + sgi_r(8, skill_level); + sgi_r(32, timeout); + sgi_rs(16, end_year); + sgi_rs(16, year); + sgi_r(8, min_players); + sgi_r(8, max_players); + sgi_r(8, nplayers); + sgi_r(8, player_idx); + sgi_r(32, globalwarming); + sgi_r(32, heating); + sgi_r(32, nuclearwinter); + sgi_r(32, cooling); + sgi_r(8, cityfactor); + sgi_r(8, diplcost); + sgi_r(8, freecost); + sgi_r(8, conquercost); + sgi_r(8, unhappysize); + + sgi_r(8, techpenalty); + sgi_r(8, foodbox); + sgi_r(8, civstyle); + sgi_r(32, seconds_to_turndone); + sgi_r(16, turn); + + if( flags & FLGSGI_global_advances ) { + for (i = 0; i < A_LAST /*game.num_tech_types */ ; i++) + dio_get_uint8(&din, &pinfo->global_advances[i]); + memcpy( &pc->game_info_cache->global_advances, &pinfo->global_advances, + sizeof(pc->game_info_cache->global_advances)); + } + else + memcpy( &pinfo->global_advances, &pc->game_info_cache->global_advances, + sizeof(pinfo->global_advances)); + + if( flags & FLGSGI_global_wonders ) { + for (i = 0; i < B_LAST /*game.num_impr_types */ ; i++) + dio_get_uint16(&din, &pinfo->global_wonders[i]); + memcpy( &pc->game_info_cache->global_wonders, &pinfo->global_wonders, + sizeof(pc->game_info_cache->global_wonders)); + } + else + memcpy( &pinfo->global_wonders, &pc->game_info_cache->global_wonders, + sizeof(pinfo->global_wonders)); + + RECEIVE_PACKET_END(pinfo); +} +void sgi_create_flags_update_cache(struct connection *pc, const struct packet_game_info *pinfo, + struct packet_game_info *gce,int *flags) +{ + *flags = 0; +#define sgi_update_flags_and_cache(m) \ + if( gce->m != pinfo->m ) { \ + gce->m = pinfo->m; \ + *flags |= FLGSGI_##m; \ + } + + sgi_update_flags_and_cache(gold); + sgi_update_flags_and_cache(tech); + sgi_update_flags_and_cache(researchcost); + sgi_update_flags_and_cache(skill_level); + sgi_update_flags_and_cache(timeout); + sgi_update_flags_and_cache(end_year); + sgi_update_flags_and_cache(year); + sgi_update_flags_and_cache(min_players); + sgi_update_flags_and_cache(max_players); + sgi_update_flags_and_cache(nplayers); + sgi_update_flags_and_cache(player_idx); + sgi_update_flags_and_cache(globalwarming); + sgi_update_flags_and_cache(heating); + sgi_update_flags_and_cache(nuclearwinter); + sgi_update_flags_and_cache(cooling); + sgi_update_flags_and_cache(cityfactor); + sgi_update_flags_and_cache(diplcost); + sgi_update_flags_and_cache(freecost); + sgi_update_flags_and_cache(conquercost); + sgi_update_flags_and_cache(unhappysize); + sgi_update_flags_and_cache(angrycitizen); + sgi_update_flags_and_cache(techpenalty); + sgi_update_flags_and_cache(foodbox); + sgi_update_flags_and_cache(civstyle); + sgi_update_flags_and_cache(spacerace); + sgi_update_flags_and_cache(seconds_to_turndone); + sgi_update_flags_and_cache(turn); + // sgi_update_flags_and_cache(); + + + if( memcmp(gce->global_advances , pinfo->global_advances , A_LAST)) { + memcpy( &gce->global_advances , &pinfo->global_advances , + sizeof(gce->global_advances)); + *flags |= FLGSGI_global_advances; + } + + if( memcmp(gce->global_wonders , pinfo->global_wonders , B_LAST)) { + memcpy( &gce->global_wonders , &pinfo->global_wonders , + sizeof(gce->global_wonders)); + *flags |= FLGSGI_global_wonders; + } + +} + + +int send_packet_short_game_info(struct connection *pc, + const struct packet_game_info *pinfo) +{ + int flags,i; + SEND_PACKET_START(PACKET_SHORT_GAME_INFO); + + sgi_create_flags_update_cache(pc, pinfo, + pc->game_info_cache ,&flags); + if( 0 == flags ) { + /* static int count=0; + freelog(LOG_DEBUG, "Not sending SGI packet, no new information(%d)", ++count ); + */ + SEND_PACKET_ABORT; + } + + dio_put_uint32(&dout, flags); + +#define sgi_(size,m) \ + if ( flags & FLGSGI_##m ) \ + { \ + dio_put_uint##size(&dout, pinfo->m); \ + } + +#define sgi_s(size,m) \ + if ( flags & FLGSGI_##m ) \ + { \ + dio_put_sint##size(&dout, pinfo->m); \ + } + + sgi_(32, gold); + sgi_(32, tech); + sgi_(8, researchcost); + sgi_(8, skill_level); + sgi_(32, timeout); + sgi_s(16, end_year); + sgi_s(16, year); + sgi_(8, min_players); + sgi_(8, max_players); + sgi_(8, nplayers); + sgi_(8, player_idx); + sgi_(32, globalwarming); + sgi_(32, heating); + sgi_(32, nuclearwinter); + sgi_(32, cooling); + sgi_(8, cityfactor); + sgi_(8, diplcost); + sgi_(8, freecost); + sgi_(8, conquercost); + sgi_(8, unhappysize); + + sgi_(8, techpenalty); + sgi_(8, foodbox); + sgi_(8, civstyle); + sgi_(32, seconds_to_turndone); + sgi_(16, turn); + + /* bool, implicit in flags + sgi_(spacerace); + sgi_(angrycitizen); + */ + + + if ( flags & FLGSGI_global_advances) + for (i = 0; i < A_LAST /*game.num_tech_types */ ; i++) + dio_put_uint8(&dout, pinfo->global_advances[i]); + + if ( flags & FLGSGI_global_wonders) + for (i = 0; i < B_LAST /*game.num_impr_types */ ; i++) + dio_put_uint16(&dout, pinfo->global_wonders[i]); + + SEND_PACKET_END; +} +#endif + /************************************************************************* ... **************************************************************************/ @@ -1097,6 +1598,10 @@ struct packet_tile_info *receive_packet_ { RECEIVE_PACKET_START(packet_tile_info, packet); +#ifdef CONFIG_STI_PACKETS + assert( ! pc->use_sti ); +#endif + dio_get_uint8(&din, &packet->x); dio_get_uint8(&din, &packet->y); dio_get_uint8(&din, &packet->type); @@ -1117,6 +1622,154 @@ struct packet_unittype_info *receive_pac RECEIVE_PACKET_END(packet); } + +#ifdef CONFIG_STI_PACKETS +/************************************************************************* + ... +**************************************************************************/ +struct packet_tile_info * +receive_packet_short_tile_info(struct connection *pc) +{ + int pack; + struct map_cache_entry *mce; + RECEIVE_PACKET_START(packet_tile_info, packet); + + assert( pc->use_sti ); + + + dio_get_uint8(&din, &packet->x); + dio_get_uint8(&din, &packet->y); + dio_get_uint8(&din, &pack); + packet->known = pack & 3; + packet->type = (pack >> 4) & 0x0f; + assert(packet->x >= 0); + assert(packet->y >= 0); + assert(packet->x < map.xsize); + assert(packet->y < map.ysize); + mce = &(pc->map_cache[packet->x*map.ysize+ packet->y]); + mce->known = packet->known; + mce->x = packet->x; + mce->y = packet->y; + mce->type = packet->type; + if( pack & (1<<2) ) // special flag + { + if( pack & (1<<3) ) + mce->special = packet->special = 0; + else { + dio_get_uint16(&din, &packet->special); + mce->special = packet->special; + } + } + else + packet->special = mce->special; + + RECEIVE_PACKET_END(packet); +} + +/************************************************************************* + should only be called with flags already set up +**************************************************************************/ +int send_packet_short_tile_info(struct connection *pc, + const struct packet_tile_info *pinfo) +{ + unsigned char pack = 0; + static int histo_flags[32],histo_flags_turn[32]; + static int miss=0, total=0, year=-1999999; + int i,fidx; + struct map_cache_entry *mce; + int flags=0; + + SEND_PACKET_START(PACKET_SHORT_TILE_INFO); + +#define MCF_SEND 0x01 +#define MCF_X 0x02 +#define MCF_Y 0x04 +#define MCF_TYPE 0x08 +#define MCF_SPECIAL 0x10 +#define MCF_KNOWN 0x20 + + assert(pinfo->x >= 0); + assert(pinfo->y >= 0); + mce = &(pc->map_cache[pinfo->x*map.ysize+ pinfo->y]); + /* if(mce->x != pinfo->x + || mce->y != pinfo->y) + { + mce->x = pinfo->x; + mce->y = pinfo->y; + flags |= MCF_SEND | MCF_X | MCF_Y ; + } + */ + + if(mce->type != pinfo->type) + { + mce->type = pinfo->type; + flags |= MCF_SEND | MCF_TYPE; + } + + if(mce->special != pinfo->special) + { + // freelog(LOG_ERROR, "specials from 0x%x to 0x%x", + // mce->special, pinfo->special); + mce->special = pinfo->special; + flags |= MCF_SEND | MCF_SPECIAL; + } + if(mce->known != pinfo->known) + { + mce->known = pinfo->known; + flags |= MCF_SEND | MCF_KNOWN; + } + if ( ! ( flags & MCF_SEND ) ) + { + // freelog(LOG_ERROR, "map tile cache hit"); + return 0; + } + // freelog(LOG_ERROR, "map tile cache miss 0x%x", flags); + + +#if 1 + // cache usage statistics + fidx = flags >>1; // 0-31 + total++; + if (flags & MCF_SEND ) + miss++; + if( game.year != year ) + { + year = game.year; + for ( i=0; i<32; i++) { + histo_flags[i] += histo_flags_turn[i]; + if ( histo_flags[i]) + { + freelog(LOG_ERROR, "map cache flags 0x%x total/last %d/%d", i <<1, + histo_flags[i], histo_flags_turn[i]); + } + } + freelog(LOG_ERROR, "map cache miss/total %d/%d", miss, total); + memset( histo_flags_turn,0,sizeof(histo_flags_turn) ); + } + histo_flags_turn[fidx] ++; +#endif + + flags = flags &(MCF_KNOWN | MCF_SPECIAL | MCF_TYPE ) ; + pack = pinfo->known & 3; //2bits + + if( flags & MCF_SPECIAL ) + { + pack |= 1<<2; //1bit + if( pinfo->special == 0 ) + pack |= 1<<3; //1bit + } + pack |= (pinfo->type & 0xf) << 4 ; //4bit + dio_put_uint8(&dout, pinfo->x); + dio_put_uint8(&dout, pinfo->y); + dio_put_uint8(&dout, pack); + if( flags & MCF_SPECIAL + && pinfo->special != 0 ) + dio_put_uint16(&dout, pinfo->special); + + SEND_PACKET_END; +} +#endif /* ifdef CONFIG_STI_PACKETS */ + /************************************************************************* ... **************************************************************************/ @@ -1125,6 +1778,11 @@ int send_packet_tile_info(struct connect { SEND_PACKET_START(PACKET_TILE_INFO); +#ifdef CONFIG_SUI_PACKETS + if ( is_server && pc->use_sti ) + return send_packet_short_tile_info(pc, pinfo); +#endif + dio_put_uint8(&dout, pinfo->x); dio_put_uint8(&dout, pinfo->y); dio_put_uint8(&dout, pinfo->type); @@ -1191,6 +1849,11 @@ int send_packet_unit_info(struct connect unsigned char pack; SEND_PACKET_START(PACKET_UNIT_INFO); +#ifdef CONFIG_SUI_PACKETS + if ( is_server && pc->use_sui ) + return send_packet_short_unit_info(pc, req); +#endif + dio_put_uint16(&dout, req->id); dio_put_uint8(&dout, req->owner); pack = (COND_SET_BIT(req->select_it, 2) | @@ -1234,6 +1897,11 @@ int send_packet_city_info(struct connect int data; SEND_PACKET_START(PACKET_CITY_INFO); +#ifdef CONFIG_SCI_PACKETS + if ( is_server && pc->use_sci ) + return send_packet_short_city_info(pc, req); +#endif + dio_put_uint16(&dout, req->id); dio_put_uint8(&dout, req->owner); dio_put_uint8(&dout, req->x); @@ -1314,6 +1982,10 @@ struct packet_city_info *receive_packet_ int data; RECEIVE_PACKET_START(packet_city_info, packet); +#ifdef CONFIG_SCI_PACKETS + assert( ! pc->use_sci); +#endif + dio_get_uint16(&din, &packet->id); dio_get_uint8(&din, &packet->owner); dio_get_uint8(&din, &packet->x); @@ -1445,6 +2117,272 @@ struct packet_short_city *receive_packet RECEIVE_PACKET_END(packet); } +#ifdef CONFIG_SUI_PACKETS +/* unit cache hash functions */ + +static struct unit_cache_entry* sui_hash_get_list (struct hash_table *ht, int hv) +{ + return (struct unit_cache_entry*) hash_lookup_data(ht, (void*)hv); +} + +static void sui_hash_insert(struct hash_table *ht, struct unit_cache_entry* cce) +{ + struct unit_cache_entry *lp; + cce->hash_value = hash_fval_keyval((void*)(int)cce->id,hash_num_buckets(ht)); + + lp = sui_hash_get_list(ht, cce->hash_value); + if( lp == NULL ) + { + cce->next = NULL; + hash_insert(ht, (void*)cce->hash_value, cce); + } + else + { + cce->next = lp->next; + lp->next = cce; + } +} +static struct unit_cache_entry *sui_hash_lookup(struct hash_table *ht, int id) +{ + struct unit_cache_entry *lp; + + lp = sui_hash_get_list(ht, hash_fval_keyval((void*)id,hash_num_buckets(ht)) ); + if( lp == NULL ) + { + return NULL; + } + else + { + do { + if ( lp->id == id) + return lp; + lp = lp->next; + } while ( lp != NULL ); + } + return NULL; +} + +void sui_create_flags_update_cache(struct connection *pc, const struct packet_unit_info *pinfo, + struct unit_cache_entry *uce,int *flags) +{ + int pack; + *flags = 0; + + pack=(pinfo->select_it ? 0x04 : 0) + | (pinfo->carried ? 0x08 : 0) + | (pinfo->veteran ? 0x10 : 0) + | (pinfo->ai ? 0x20 : 0) + | (pinfo->paradropped ? 0x40 : 0) + | (pinfo->connecting ? 0x80 : 0); + + if( uce->pack != pack ) { + uce->pack = pack; + *flags |= FLGSUI_pack; + } + +#define sui_update_flags_and_cache(m) \ + if( uce->m != pinfo->m ) { \ + uce->m = pinfo->m; \ + *flags |= FLGSUI_##m; \ + } + + sui_update_flags_and_cache(x); + sui_update_flags_and_cache(y); + sui_update_flags_and_cache(owner); + sui_update_flags_and_cache(type); + sui_update_flags_and_cache(movesleft); + sui_update_flags_and_cache(hp); + sui_update_flags_and_cache(upkeep); + sui_update_flags_and_cache(upkeep_food); + sui_update_flags_and_cache(upkeep_gold); + sui_update_flags_and_cache(unhappiness); + sui_update_flags_and_cache(activity); + sui_update_flags_and_cache(activity_count); + sui_update_flags_and_cache(goto_dest_x); + sui_update_flags_and_cache(goto_dest_y); + sui_update_flags_and_cache(packet_use); + sui_update_flags_and_cache(fuel); + sui_update_flags_and_cache(homecity); + sui_update_flags_and_cache(activity_target); + sui_update_flags_and_cache(info_city_id); + sui_update_flags_and_cache(serial_num); + // sui_update_flags_and_cache(); + + +} +/************************************************************************* + ... +**************************************************************************/ +int send_packet_short_unit_info(struct connection *pc, + const struct packet_unit_info *req) +{ + struct unit_cache_entry *uce; + int flags; + SEND_PACKET_START(PACKET_SHORT_UNIT_INFO); + + assert( pc->unit_cache != NULL ); + assert( pc->use_sui ); + + dio_put_uint16(&dout, req->id); + + uce = sui_hash_lookup(pc->unit_cache, req->id); + if (uce == NULL) + { + freelog(LOG_DEBUG, "uci, creating cache entry: %d", req->id ); + uce = fc_malloc(sizeof(struct unit_cache_entry)); + memset( uce, 0, sizeof(struct unit_cache_entry)); + uce->id = req->id; + sui_hash_insert(pc->unit_cache, uce); + } + else + { + // sanity check the cache entry + // x,y,,owner + // assert(uce-> == req->); + } + assert(uce != NULL); + + sui_create_flags_update_cache(pc, req, uce, &flags); + + if( 0 == flags ) { + /* static int count=0; + freelog(LOG_DEBUG, "Not sending SUI packet, no new information(%d)", ++count ); + */ + SEND_PACKET_ABORT; + } + + dio_put_uint32(&dout, flags); +#define sui_check_flag_send_value(size,m) \ + if ( flags & FLGSUI_##m ) \ + { \ + dio_put_uint##size(&dout, req->m); \ + } + + + sui_check_flag_send_value(8,x); + sui_check_flag_send_value(8,y); + sui_check_flag_send_value(8,owner); + sui_check_flag_send_value(8,type); + sui_check_flag_send_value(8,movesleft); + sui_check_flag_send_value(8,hp); + sui_check_flag_send_value(8,upkeep); + sui_check_flag_send_value(8,upkeep_food); + sui_check_flag_send_value(8,upkeep_gold); + sui_check_flag_send_value(8,unhappiness); + sui_check_flag_send_value(8,activity); + sui_check_flag_send_value(8,activity_count); + sui_check_flag_send_value(8,goto_dest_x); + sui_check_flag_send_value(8,goto_dest_y); + sui_check_flag_send_value(8,packet_use); + sui_check_flag_send_value(8,fuel); + // sui_check_flag_send_value(8,); + sui_check_flag_send_value(16,homecity); + sui_check_flag_send_value(16,activity_target); + sui_check_flag_send_value(16,info_city_id); + sui_check_flag_send_value(16,serial_num); + // sui_check_flag_send_value(16,); + + if(flags & FLGSUI_pack) + { + dio_put_uint8(&dout, uce->pack); + } + SEND_PACKET_END; +} +/************************************************************************* + ... +**************************************************************************/ +struct packet_unit_info * +receive_packet_short_unit_info(struct connection *pc) +{ + int pack,flags = 0; + struct unit_cache_entry *uce; + + RECEIVE_PACKET_START(packet_unit_info, pinfo); + + assert( pc->use_sui ); + + dio_get_uint16(&din, &pinfo->id); + + dio_get_uint32(&din, &flags); + + assert(pc->unit_cache != NULL); + /*if(pc->unit_cache == NULL) + pc->unit_cache = hash_new_nentries(&hash_fval_keyval,&hash_fcmp_keyval,911) ; + */ + uce = sui_hash_lookup(pc->unit_cache, pinfo->id); + if (uce == NULL) + { + freelog(LOG_DEBUG, "uci, creating cache entry: %d", pinfo->id ); + + uce = fc_malloc(sizeof(struct unit_cache_entry)); + memset( uce, 0, sizeof(struct unit_cache_entry)); + uce->id = pinfo->id; + sui_hash_insert(pc->unit_cache, uce); + } + else + { + // sanity check the cache entry + // x,y,,owner + // assert(uce-> == req->); + } + assert(uce != NULL); + + +#define sui_check_flag_update_cache(siz,m) \ + if ( flags & FLGSUI_##m ) \ + { \ + dio_get_uint##siz(&din, (int*)&pinfo->m); \ + /* freelog(LOG_ERROR,"sui, cfuc, %3d new " #m " %d", pinfo->id, pinfo->m);*/ \ + uce->m = pinfo->m; \ + } \ + else \ + { \ + pinfo->m = uce->m; \ + /* freelog(LOG_ERROR,"sui, cfuc, %3d old " #m " %d", pinfo->id, pinfo->m);*/ \ + } + sui_check_flag_update_cache(8,x); + sui_check_flag_update_cache(8,y); + sui_check_flag_update_cache(8,owner); + sui_check_flag_update_cache(8,type); + sui_check_flag_update_cache(8,movesleft); + sui_check_flag_update_cache(8,hp); + sui_check_flag_update_cache(8,upkeep); + sui_check_flag_update_cache(8,upkeep_food); + sui_check_flag_update_cache(8,upkeep_gold); + sui_check_flag_update_cache(8,unhappiness); + sui_check_flag_update_cache(8,activity); + sui_check_flag_update_cache(8,activity_count); + sui_check_flag_update_cache(8,goto_dest_x); + sui_check_flag_update_cache(8,goto_dest_y); + sui_check_flag_update_cache(8,packet_use); + sui_check_flag_update_cache(8,fuel); + sui_check_flag_update_cache(16,homecity); + sui_check_flag_update_cache(16,activity_target); + sui_check_flag_update_cache(16,info_city_id); + sui_check_flag_update_cache(16,serial_num); + + if( flags & FLGSUI_pack) { + int uc; + dio_get_uint8(&din, &uc); + uce->pack = uc; + } + + pack = uce->pack; + + pinfo->select_it = (pack&0x04) ? 1 : 0; + pinfo->carried = (pack&0x08) ? 1 : 0; + pinfo->veteran = (pack&0x10) ? 1 : 0; + pinfo->ai = (pack&0x20) ? 1 : 0; + pinfo->paradropped = (pack&0x40) ? 1 : 0; + pinfo->connecting = (pack&0x80) ? 1 : 0; + + + RECEIVE_PACKET_END(pinfo); +} + +#endif CONFIG_SUI_PACKETS + + /************************************************************************* ... **************************************************************************/ @@ -1453,6 +2391,12 @@ struct packet_unit_info *receive_packet_ int pack; RECEIVE_PACKET_START(packet_unit_info, packet); +#ifdef CONFIG_SUI_PACKETS + /* Not, because client sends this to server, too. --yon + assert( ! pc->use_sui ); + */ +#endif + dio_get_uint16(&din, &packet->id); dio_get_uint8(&din, &packet->owner); dio_get_uint8(&din, &pack); @@ -1503,7 +2447,189 @@ struct packet_new_year *receive_packet_n RECEIVE_PACKET_END(packet); } +#ifdef CONFIG_SPI_PACKETS +/************************************************************************* +... +**************************************************************************/ +int calculate_delta_flags_update_cache( struct pinfo_cache_entry* pic, + const struct packet_player_info *pinfo, + unsigned char combined) +{ + int i,j,flags = 0 ; + + if ( pic == NULL ) + return 0xffffffff; + if( strlen(pinfo->name) != strlen(pic->name) + || strncmp( (const char *)&pinfo->name, (const char*)&pic->name, + MAX_LEN_NAME) ) + { + freelog(LOG_ERROR, "spi, name cache miss: %d %s(%s)", + pinfo->playerno,pinfo->name, + pic->name); + memcpy(&pic->name, &pinfo->name,MAX_LEN_NAME); + flags |= FLGSPI_name; + } + else + // freelog(LOG_ERROR, "spi, name cache hit: %s/%s", pinfo->name, pic->name); + + if( pic->combined != combined ) { + pic->combined = combined; + flags |= FLGSPI_combined; + } +#define spi_update_flags_and_cache(m) \ + if( pic->m != pinfo->m ) { \ + pic->m = pinfo->m; \ + flags |= FLGSPI_##m; \ + } + + spi_update_flags_and_cache(government); + spi_update_flags_and_cache(embassy); + spi_update_flags_and_cache(city_style); + spi_update_flags_and_cache(nation); + spi_update_flags_and_cache(nturns_idle); + spi_update_flags_and_cache(reputation); + spi_update_flags_and_cache(gold); + spi_update_flags_and_cache(tax); + spi_update_flags_and_cache(science); + spi_update_flags_and_cache(luxury); + spi_update_flags_and_cache(bulbs_researched); + spi_update_flags_and_cache(techs_researched); + spi_update_flags_and_cache(researching); + spi_update_flags_and_cache(future_tech); + spi_update_flags_and_cache(gives_shared_vision); + spi_update_flags_and_cache(tech_goal); + spi_update_flags_and_cache(barbarian_type); + + + if( strncmp(pic->inventions, pinfo->inventions, sizeof(pic->inventions)) ) + { + //freelog(LOG_ERROR, "spi, invention cache length miss: %d/%d", + // pic->number_inventions, strlen( pinfo->inventions)); + // pic->number_inventions = strlen( pinfo->inventions) ; + memcpy( pic->inventions, pinfo->inventions, sizeof(pic->inventions)); + flags |= FLGSPI_inventions; /* YYY send only add/remove invention */ + } + else + if( memcmp(pic->inventions , pinfo->inventions , sizeof(pic->inventions))) + { + // freelog(LOG_ERROR, "spi, invention cache content miss: %d/%d", + // pic->number_inventions, strlen( pinfo->inventions)); + flags |= FLGSPI_inventions; + } + + for (i = 0; i < game.nplayers //MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS +; i++) { + if ( pinfo->diplstates[i].turns_left != pic->diplstates[i].turns_left ) { + flags |= FLGSPI_diplstates; + pic->diplstates[i].turns_left = pinfo->diplstates[i].turns_left; + } + combined = (pinfo->diplstates[i].type & 7 ) + | ( (pinfo->diplstates[i].has_reason_to_cancel & 3) << 3 ) + | ( ( (pinfo->diplstates[i].turns_left > 0) &1) << 5 ) ; /*YYY*/ + if ( combined != pic->diplstates[i].combined ) { + flags |= FLGSPI_diplstates; + pic->diplstates[i].combined = combined; + } + } + + return flags; +} +/************************************************************************* +... +**************************************************************************/ +int send_packet_short_player_info(struct connection *pc, + const struct packet_player_info *pinfo) +{ + struct pinfo_cache_entry *pic; + unsigned char combined ; + int i; + int flags; /* 32bit */ + + SEND_PACKET_START(PACKET_SHORT_PLAYER_INFO); + + assert( pc->use_spi ); + + dio_put_uint8(&dout, pinfo->playerno); + + combined = (pinfo->is_alive ? 1 : 0) + | (pinfo->turn_done ? 2 : 0) + | (pinfo->is_connected ? 4: 0) + | (pinfo->ai ? 8 : 0) + | (pinfo->is_male ? 32 : 0) + | (pinfo->revolution ? 64 : 0); + + pic = &pc->pinfo_cache[pinfo->playerno]; + + flags = calculate_delta_flags_update_cache( pic, + pinfo, combined); + + if( 0 == flags ) { + /* static int count=0; + freelog(LOG_DEBUG, "Not sending SPI packet, no new information(%d)", ++count ); + */ + SEND_PACKET_ABORT; + } + + dio_put_uint32(&dout, flags); + //freelog(LOG_ERROR, "spi, flags: 0x%x", flags); + + if ( flags & FLGSPI_name ) { + // freelog(LOG_ERROR, " including name in spi (%s)", pinfo->name); + dio_put_string(&dout, pinfo->name); + } else + ;//freelog(LOG_ERROR, " omitting name from spi"); + + +#define spi_send(size,m) \ + if ( flags & FLGSPI_##m ) \ + { \ + dio_put_uint##size(&dout, pinfo->m); \ + } + + spi_send(8, government); + spi_send(32, embassy); + spi_send(8, city_style); + spi_send(8, nation); + spi_send(16, nturns_idle); + + if ( flags & FLGSPI_combined ) { + dio_put_uint8(&dout, combined); + } + + spi_send(32, reputation); + spi_send(32, gold); + spi_send(8, tax); + spi_send(8, science); + spi_send(8, luxury); + spi_send(32, bulbs_researched); + spi_send(32, techs_researched); + spi_send(8, researching); + spi_send(16, future_tech); + spi_send(32, gives_shared_vision); + spi_send(8, tech_goal); + spi_send(8, barbarian_type); + if ( flags & FLGSPI_inventions ) { + //freelog(LOG_ERROR, " inventions sent: %d", strlen(pinfo->inventions)); + /* pic->number_inventions holds the number of inventions, uselessly. */ + dio_put_bit_string(&dout, (char*)pinfo->inventions); + } + else + ;//freelog(LOG_ERROR, " inventions skipped: %d", strlen(pinfo->inventions)); + + if ( flags & FLGSPI_diplstates ) { + dio_put_uint8(&dout, game.nplayers); + for (i = 0; i < game.nplayers //MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS + ; i++) { + /* see the flags computing function for the syntax of combined */ + dio_put_uint8(&dout, pic->diplstates[i].combined); + if ( pinfo->diplstates[i].turns_left > 0 ) + dio_put_uint16(&dout, pinfo->diplstates[i].turns_left); + } + } + SEND_PACKET_END; +} +#endif /* CONFIG_SPI_PACKETS */ /************************************************************************** ... @@ -1572,6 +2698,120 @@ int send_packet_join_game_reply(struct c SEND_PACKET_END; } +#ifdef CONFIG_SPI_PACKETS +/************************************************************************* +... +**************************************************************************/ +struct packet_player_info * +receive_packet_short_player_info(struct connection *pc) +{ + struct pinfo_cache_entry *pic; + int i; + int len,combined,flags; + + RECEIVE_PACKET_START(packet_player_info, pinfo); + + assert( pc->use_spi ); + + dio_get_uint8(&din, &pinfo->playerno); + dio_get_uint32(&din, &flags); + + pic = &pc->pinfo_cache[pinfo->playerno]; + + if ( flags & FLGSPI_name ) + { + dio_get_string(&din, pinfo->name, sizeof(pinfo->name)); + strncpy(pic->name, pinfo->name, sizeof(pic->name)); + } + else + memcpy(pinfo->name, pic->name, sizeof(pinfo->name)); + +#define check_flag_update_cache(size,m) \ + if ( flags & FLGSPI_##m ) \ + { \ + dio_get_uint##size(&din, &pinfo->m); \ + pic->m = pinfo->m;\ + } \ + else \ + pinfo->m = pic->m; \ + + + check_flag_update_cache(8,government); + check_flag_update_cache(32,embassy); + check_flag_update_cache(8,city_style); + check_flag_update_cache(8,nation); + check_flag_update_cache(16,nturns_idle); + if ( flags & FLGSPI_combined ) + { + dio_get_uint8(&din, &combined); + pic->combined = combined; + } + else + { + combined = pic->combined; + } + pinfo->is_alive = combined & 1 ? 1 : 0; + pinfo->turn_done = combined & 2 ? 1 : 0; + pinfo->is_connected = combined & 4 ? 1 : 0; + pinfo->ai = combined & 8 ? 1 : 0; + pinfo->is_male = combined & 32 ? 1 : 0; + pinfo->revolution = combined & 64 ? 1 : 0; + + check_flag_update_cache(32,reputation); + check_flag_update_cache(32,gold); + check_flag_update_cache(8,tax); + check_flag_update_cache(8,science); + check_flag_update_cache(8,luxury); + check_flag_update_cache(32,bulbs_researched); + check_flag_update_cache(32,techs_researched); + check_flag_update_cache(8,researching); + check_flag_update_cache(16,future_tech); + check_flag_update_cache(32,gives_shared_vision); + check_flag_update_cache(8,tech_goal); + check_flag_update_cache(8,barbarian_type); + + if ( flags & FLGSPI_inventions ) + { + dio_get_bit_string(&din, pinfo->inventions, sizeof(pinfo->inventions) ); + //pic->number_inventions = strlen ( pinfo->inventions ) ; + memcpy( pic->inventions, pinfo->inventions, sizeof(pic->inventions)); + } + else + { + memcpy( pinfo->inventions, pic->inventions, sizeof(pic->inventions)); + } + + if ( flags & FLGSPI_diplstates ) { + dio_get_uint8(&din, &len); + if ( len != game.nplayers ) { + freelog(LOG_ERROR, __FUNCTION__ ": number of players in packet: %d local: %d", + len, game.nplayers); + } + + for (i = 0; i < len; i++) { + dio_get_uint8(&din, &combined ); + pic->diplstates[i].combined = combined; + pinfo->diplstates[i].type = combined & 7; + pinfo->diplstates[i].has_reason_to_cancel = ( combined & 0x18 ) >> 3; + if( combined & 0x20 ) + dio_get_uint16(&din, &pinfo->diplstates[i].turns_left); + else + pinfo->diplstates[i].turns_left = 0; + pic->diplstates[i].turns_left = pinfo->diplstates[i].turns_left; + } + } else { + for (i = 0; i < game.nplayers; i++) { + combined = pic->diplstates[i].combined; + pinfo->diplstates[i].type = combined & 7; + pinfo->diplstates[i].has_reason_to_cancel = ( combined & 0x18 ) >> 3; + pinfo->diplstates[i].turns_left = pic->diplstates[i].turns_left; + } + } + + pinfo->flags = flags; + RECEIVE_PACKET_END(pinfo); +} +#endif /* CONFIG_SPI_PACKETS */ /************************************************************************** ... @@ -2001,6 +3241,632 @@ receive_packet_ruleset_tech(struct conne RECEIVE_PACKET_END(packet); } +#ifdef CONFIG_SCI_PACKETS +/* city cache hash functions */ + +static struct city_cache_entry* sci_hash_get_list (struct hash_table *ht, int hv) +{ + return (struct city_cache_entry*) hash_lookup_data(ht, (void*)hv); +} + +static void sci_hash_insert(struct hash_table *ht, struct city_cache_entry* cce) +{ + struct city_cache_entry *lp; + cce->hash_value = hash_fval_keyval((void*)(int)cce->id, hash_num_buckets(ht)); + + lp = sci_hash_get_list(ht, cce->hash_value); + if( lp == NULL ) + { + cce->next = NULL; + hash_insert(ht, (void*)cce->hash_value, cce); + } + else + { + cce->next = lp->next; + lp->next = cce; + } +} +static struct city_cache_entry *sci_hash_lookup(struct hash_table *ht, int id) +{ + struct city_cache_entry *lp; + + lp = sci_hash_get_list(ht, hash_fval_keyval((void*)id, hash_num_buckets(ht))); + if( lp == NULL ) + { + return NULL; + } + else + { + do { + if ( lp->id == id) + return lp; + lp = lp->next; + } while ( lp != NULL ); + } + return NULL; +} +/************************************************************************* + Called by the send function to calculate the flags values to be sent (and +hence control what is sent) and to update the local cache to the new values. +**************************************************************************/ +static void calculate_delta_flags_update_cache_short_city( struct connection* pc, + const struct packet_city_info *pinfo, + struct city_cache_entry* pcc, + int *flags, int *flags2) +{ + unsigned char data; + *flags = 0; + *flags2 = 0; + assert(pcc != NULL); + if( strncmp( (const char *)pinfo->name, (const char*)pcc->name, + MAX_LEN_NAME) ) + { + freelog(LOG_ERROR, "sci, name cache miss: %s(%d/%d) %s(%d/%d)", + pinfo->name, pinfo->id, + hash_fval_keyval( (void*)pinfo->id, hash_num_buckets(pc->city_cache)), + pcc->name, pcc->id, pcc->hash_value); + memcpy(&pcc->name, &pinfo->name, MAX_LEN_NAME); + *flags2 |= FLGSCI_2_name; + } + else + ;// freelog(LOG_ERROR, "sci, name cache hit: %s/%s", pinfo->name, pcc->name); + +#define sci_update_flags2_and_cache(m) \ + if( pcc->m != pinfo->m ) { \ + pcc->m = pinfo->m; \ + *flags2 |= FLGSCI_2_##m; \ + } + sci_update_flags2_and_cache(x); + sci_update_flags2_and_cache(y); + sci_update_flags2_and_cache(owner); + sci_update_flags2_and_cache(turn_founded); + if ( *flags2 ) + *flags |= FLGSCI_flags2; + +#define sci_update_flags_and_cache(m) \ + if( pcc->m != pinfo->m ) { \ + pcc->m = pinfo->m; \ +/* freelog(LOG_ERROR,"sci, ufac, " #m " %d", pinfo->m);*/ \ + *flags |= FLGSCI_##m; \ + } + + sci_update_flags_and_cache(size); + sci_update_flags_and_cache(ppl_elvis); + sci_update_flags_and_cache(ppl_scientist); + sci_update_flags_and_cache(ppl_taxman); + sci_update_flags_and_cache(food_prod); + sci_update_flags_and_cache(food_surplus); + sci_update_flags_and_cache(shield_prod); + sci_update_flags_and_cache(shield_surplus); + sci_update_flags_and_cache(trade_prod); + sci_update_flags_and_cache(tile_trade); + sci_update_flags_and_cache(corruption); + sci_update_flags_and_cache(luxury_total); + sci_update_flags_and_cache(tax_total); + sci_update_flags_and_cache(science_total); + sci_update_flags_and_cache(food_stock); + sci_update_flags_and_cache(shield_stock); + sci_update_flags_and_cache(pollution); + sci_update_flags_and_cache(currently_building); + sci_update_flags_and_cache(turn_last_built); + sci_update_flags_and_cache(turn_changed_target); + sci_update_flags_and_cache(changed_from_id); + sci_update_flags_and_cache(before_change_shields); + sci_update_flags_and_cache(disbanded_shields); + sci_update_flags_and_cache(caravan_shields); + sci_update_flags_and_cache(city_options); + + // sci_update_flags_and_cache(_); + /* todo: + trade + */ + + for (data = 0; data < 5; data++) { //c check direction + if ( pcc->ppl_happy[data] == pinfo->ppl_happy[data] + && pcc->ppl_content[data] == pinfo->ppl_content[data] + && pcc->ppl_unhappy[data] == pinfo->ppl_unhappy[data] + && pcc->ppl_angry[data] == pinfo->ppl_angry[data] ) + continue; + *flags |= FLGSCI_ppl; + pcc->ppl_happy[data] = pinfo->ppl_happy[data]; + pcc->ppl_content[data] = pinfo->ppl_content[data]; + pcc->ppl_unhappy[data] = pinfo->ppl_unhappy[data]; + pcc->ppl_angry[data] = pinfo->ppl_angry[data]; + } + + if( memcmp(pcc->city_map, pinfo->city_map, sizeof(pcc->city_map) ) ) + { + memcpy(pcc->city_map, pinfo->city_map, sizeof(pcc->city_map) ); + *flags |= FLGSCI_citymap; + } + + for(data=0; data < NUM_TRADEROUTES; data++) + { + if(pinfo->trade[data] == pcc->trade[data] + && pinfo->trade_value[data] == pcc->trade_value[data] ) + continue; + *flags |= FLGSCI_trade; + pcc->trade_value[data] = pinfo->trade_value[data]; + pcc->trade[data] = pinfo->trade[data]; + } + + data = pinfo->is_building_unit?1:0 ; + data |= pinfo->did_buy?2:0; + data |= pinfo->did_sell?4:0; + data |= pinfo->was_happy?8:0; + data |= pinfo->airlift?16:0; + data |= pinfo->diplomat_investigate?32:0; + data |= pinfo->changed_from_is_unit?64:0; + + if( pcc->flags1 != data ) + { + pcc->flags1 = data; + *flags |= FLGSCI_flags1; + } + + if( memcmp( &pcc->worklist, &pinfo->worklist, sizeof(pcc->worklist) ) ) + { // this might give false positives + memcpy(&pcc->worklist, &pinfo->worklist, sizeof(pcc->worklist) ); + *flags |= FLGSCI_worklist; + } + + if( strlen(pinfo->improvements) != strlen(pcc->improvements) + || strncmp( (const char *)pinfo->improvements, (const char*)pcc->improvements, + B_LAST+1) ) + { + freelog(LOG_ERROR, "sci, improvement cache miss: %s(%d/%d) %s(%d/%d)", + pinfo->name, pinfo->id, + hash_fval_keyval((void*)pinfo->id, hash_num_buckets(pc->city_cache)), + pcc->name, pcc->id, pcc->hash_value); + memcpy(&pcc->improvements, &pinfo->improvements, strlen(pinfo->improvements) +1 ); + *flags |= FLGSCI_improvements; + } + else + ;// freelog(LOG_ERROR, "sci, improvement cache hit: %s/%s", pinfo->name, pcc->name); +} +/************************************************************************* +... +**************************************************************************/ +int send_packet_short_city_info(struct connection *pc, + const struct packet_city_info *req) +{ + int data,flags,flags2; // flags2 is 8 bit + struct city_cache_entry *cce; +#ifdef CONFIG_SCI_PACKETS_CRC + uLong adler = adler32(0L, Z_NULL, 0); +#endif + + SEND_PACKET_START(PACKET_SHORT_CITY_INFO); + + assert( pc->use_sci ); + assert( pc->city_cache != NULL ); + + dio_put_uint16(&dout, req->id); + + cce = sci_hash_lookup(pc->city_cache, req->id); + if (cce == NULL) + { + freelog(LOG_ERROR, "sci, creating cache entry: %d/%s", req->id, req->name); + + cce = fc_malloc(sizeof(struct city_cache_entry)); + memset( cce, 0, sizeof(struct city_cache_entry)); + cce->id = req->id; + sci_hash_insert(pc->city_cache, cce); + } + else + { + // sanity check the cache entry + // x,y,,owner + //assert(cce->x == req->x); + } + assert(cce != NULL); + + calculate_delta_flags_update_cache_short_city(pc, req, cce, &flags, &flags2); + + if( 0 == flags ) { + /* static int count=0; + freelog(LOG_DEBUG, "Not sending SCI packet, no new information(%d)", ++count ); + */ + SEND_PACKET_ABORT; + } + +#ifdef CONFIG_SCI_PACKETS_CRC + /* clear the random parts of the packet. Will bomb horribly for char* + */ +#define clr_str(str) \ + memset((void*)str +strlen(str), 0, sizeof(str)-strlen(str)); + clr_str(req->name); + clr_str(req->worklist.name); + clr_str(req->improvements); + // (*(int*)req->flags) = flags; /* const * to * cast */ + adler = adler32(adler, (char*)req, sizeof(*req)); + flags2 |= FLGSCI_2_crc; + flags |= FLGSCI_flags2; +#endif + + dio_put_uint32(&dout, flags); + if( flags & FLGSCI_flags2 ) + dio_put_uint8(&dout, flags2); + +#if 1 + { + static int packets = 0; + static struct { + int hits; + } hit_stat[40]; + int i; + + if( 0 || 0 == packets) + { + // freelog(LOG_ERROR, "sci cache zeroing counters"); + memset(&hit_stat, 0, sizeof(hit_stat)); + } + packets++; + + for( i=0; i<32; i++) + if (flags & 1<m); \ + /*cce->m=req->m;*/ \ + } + +#define check_flag2_send_value(size,m) \ + if ( flags2 & FLGSCI_2_##m ) \ + { \ + dio_put_uint##size(&dout, req->m); \ + /*cce->m=req->m;*/ \ + } + + check_flag2_send_value(8,owner); + check_flag2_send_value(8,x); + check_flag2_send_value(8,y); + check_flag2_send_value(16,turn_founded); + if( flags2 & FLGSCI_2_name ) + { + dio_put_string(&dout, req->name); + } + + check_flag_send_value(8,size); + check_flag_send_value(8,ppl_elvis); + check_flag_send_value(8,ppl_scientist); + check_flag_send_value(8,ppl_taxman); + check_flag_send_value(8,food_prod); + check_flag_send_value(8,food_surplus); + check_flag_send_value(16,shield_prod); + check_flag_send_value(16,shield_surplus); + check_flag_send_value(16,trade_prod); + check_flag_send_value(16,corruption); + check_flag_send_value(16,luxury_total); + check_flag_send_value(16,tax_total); + check_flag_send_value(16,science_total); + check_flag_send_value(16,food_stock); + check_flag_send_value(16,shield_stock); + check_flag_send_value(16,pollution); + check_flag_send_value(8,currently_building); + check_flag_send_value(8,changed_from_id); + check_flag_send_value(16,before_change_shields); + check_flag_send_value(16,disbanded_shields); + check_flag_send_value(16,caravan_shields); + /* only 8 options allowed before need to extend protocol */ + check_flag_send_value(8,city_options); + check_flag_send_value(16,tile_trade); + + if ( flags & FLGSCI_turn_last_built ) + dio_put_sint16(&dout, req->turn_last_built); + if ( flags & FLGSCI_turn_changed_target ) + dio_put_sint16(&dout, req->turn_changed_target); + + + + if( flags & FLGSCI_worklist ) + { + dio_put_worklist(&dout, &req->worklist, TRUE); + } + + if( flags & FLGSCI_ppl ) + for (data = 0; data < 5; data++) { + dio_put_uint8(&dout, req->ppl_angry[data]); + dio_put_uint8(&dout, req->ppl_happy[data]); + dio_put_uint8(&dout, req->ppl_content[data]); + dio_put_uint8(&dout, req->ppl_unhappy[data]); + } + + + if( flags & FLGSCI_flags1 ) + { + data=req->is_building_unit?1:0; + data|=req->did_buy?2:0; + data|=req->did_sell?4:0; + data|=req->was_happy?8:0; + data|=req->airlift?16:0; + data|=req->diplomat_investigate?32:0; + data|=req->changed_from_is_unit?64:0; + dio_put_uint8(&dout, data); + } + + + if( flags & FLGSCI_citymap ) + { + dio_put_city_map(&dout, (char*)req->city_map); + } + + if( flags & FLGSCI_improvements ) + { + dio_put_bit_string(&dout, (char*)req->improvements); + } + + + /* see comment in receive function */ + if( flags & FLGSCI_trade ) + for(data=0 ; data < NUM_TRADEROUTES ; data++) { + if(req->trade[data]) { + dio_put_uint16(&dout, req->trade[data]); + dio_put_uint8(&dout,req->trade_value[data]); + } + } + +#ifdef CONFIG_SCI_PACKETS_CRC + if( flags2 & FLGSCI_2_crc ) + dio_put_uint32(&dout, adler); +#endif + + SEND_PACKET_END; +} + +/************************************************************************* +... +**************************************************************************/ +struct packet_city_info * +receive_packet_short_city_info(struct connection *pc) +{ + struct city_cache_entry *cce; + int data,flags, flags2; /* flags2 is 8 bit */ + struct hash_table *ht; + + RECEIVE_PACKET_START(packet_city_info, pinfo); + + assert( pc->use_sci ); + + dio_get_uint16(&din, &pinfo->id); + dio_get_uint32(&din, &flags); + if ( flags & FLGSCI_flags2 ) + dio_get_uint8(&din, &flags2); + else + flags2 = 0 ; + + ht = pc->city_cache; + + cce = sci_hash_lookup(ht,pinfo->id); + if( cce == NULL) + { + cce = fc_malloc(sizeof(struct city_cache_entry)); + memset( cce, 0, sizeof(struct city_cache_entry)); + cce->id = pinfo->id; + cce->hash_value = hash_fval_keyval((void*)(int)cce->id, hash_num_buckets(ht)); + sci_hash_insert(ht, cce); + } + +#define sci_check_flag_update_cache(siz,m) \ + if ( flags & FLGSCI_##m ) \ + { \ + dio_get_uint##siz(&din, &pinfo->m); \ +/* freelog(LOG_ERROR,"sci, cfuc, %3d new " #m " %d", pinfo->id, pinfo->m);*/ \ + cce->m = pinfo->m;\ + } \ + else \ + { \ + pinfo->m = cce->m; \ +/* freelog(LOG_ERROR,"sci, cfuc, %3d old " #m " %d", pinfo->id, pinfo->m);*/ \ + } + +#define sci_check_flag2_update_cache(siz,m) \ + if ( flags2 & FLGSCI_2_##m ) \ + { \ + dio_get_uint##siz(&din, &pinfo->m); \ +/* freelog(LOG_ERROR,"sci, cfuc, %3d new " #m " %d", pinfo->id, pinfo->m);*/ \ + cce->m = pinfo->m;\ + } \ + else \ + { \ + pinfo->m = cce->m; \ +/* freelog(LOG_ERROR,"sci, cfuc, %3d old " #m " %d", pinfo->id, pinfo->m);*/ \ + } + + sci_check_flag2_update_cache(8,owner); + sci_check_flag2_update_cache(8,x); + sci_check_flag2_update_cache(8,y); + sci_check_flag2_update_cache(16,turn_founded); + if ( flags2 & FLGSCI_2_name ) + { + dio_get_string(&din, pinfo->name, sizeof(pinfo->name)); + strncpy(cce->name, pinfo->name, sizeof(cce->name)); + } + else + memcpy(pinfo->name, cce->name, sizeof(pinfo->name)); + + sci_check_flag_update_cache(8,size); + sci_check_flag_update_cache(8,ppl_elvis); + sci_check_flag_update_cache(8,ppl_scientist); + sci_check_flag_update_cache(8,ppl_taxman); + sci_check_flag_update_cache(8,food_prod); + sci_check_flag_update_cache(8,food_surplus); + if(pinfo->food_surplus > 127) + cce->food_surplus = pinfo->food_surplus -= 256; + sci_check_flag_update_cache(16,shield_prod); + sci_check_flag_update_cache(16,shield_surplus); + if(pinfo->shield_surplus > 32767) + cce->shield_surplus = pinfo->shield_surplus -= 65536; + sci_check_flag_update_cache(16,trade_prod); + sci_check_flag_update_cache(16,corruption); + sci_check_flag_update_cache(16,luxury_total); + sci_check_flag_update_cache(16,tax_total); + sci_check_flag_update_cache(16,science_total); + sci_check_flag_update_cache(16,food_stock); + sci_check_flag_update_cache(16,shield_stock); + sci_check_flag_update_cache(16,pollution); + sci_check_flag_update_cache(8,currently_building); + sci_check_flag_update_cache(8,changed_from_id); + sci_check_flag_update_cache(16,before_change_shields); + sci_check_flag_update_cache(16,disbanded_shields); + sci_check_flag_update_cache(16,caravan_shields); + /* only 8 options allowed before need to extend protocol */ + sci_check_flag_update_cache(8,city_options); + sci_check_flag_update_cache(16,tile_trade); + + if ( flags & FLGSCI_turn_last_built ) + { + dio_get_sint16(&din, &pinfo->turn_last_built); + // freelog(LOG_ERROR,"sci, cfuc, turn_last_built %d", pinfo->turn_last_built); + cce->turn_last_built = pinfo->turn_last_built; + } + else + pinfo->turn_last_built = cce->turn_last_built; + + if ( flags & FLGSCI_turn_changed_target ) + { + dio_get_sint16(&din, &pinfo->turn_changed_target); + // freelog(LOG_ERROR,"sci, cfuc, turn_changed_target %d", pinfo->turn_changed_target); + cce->turn_changed_target = pinfo->turn_changed_target; + } + else + pinfo->turn_changed_target = cce->turn_changed_target; + + + + if ( flags & FLGSCI_worklist ) + { + dio_get_worklist(&din, &pinfo->worklist); + memcpy(&cce->worklist, &pinfo->worklist, sizeof(cce->worklist)); + } + else + memcpy(&pinfo->worklist, &cce->worklist,sizeof(cce->worklist)); + + + if( flags & FLGSCI_ppl ) + for(data=0; data < 5; data++) { + dio_get_uint8(&din, &pinfo->ppl_angry[data]); + dio_get_uint8(&din, &pinfo->ppl_happy[data]); + dio_get_uint8(&din, &pinfo->ppl_content[data]); + dio_get_uint8(&din, &pinfo->ppl_unhappy[data]); + cce->ppl_angry[data] = pinfo->ppl_angry[data]; + cce->ppl_happy[data] = pinfo->ppl_happy[data]; + cce->ppl_content[data] = pinfo->ppl_content[data]; + cce->ppl_unhappy[data] = pinfo->ppl_unhappy[data]; + } + else + { + for(data=0; data < 5; data++) { + pinfo->ppl_angry[data] = cce->ppl_angry[data]; + pinfo->ppl_happy[data] = cce->ppl_happy[data]; + pinfo->ppl_content[data] = cce->ppl_content[data]; + pinfo->ppl_unhappy[data] = cce->ppl_unhappy[data]; + } + } + + if( flags & FLGSCI_flags1 ) + { + dio_get_uint8(&din, &data); + cce->flags1 = data; + } + else + data = cce->flags1; + + pinfo->is_building_unit = data&1; + pinfo->did_buy = (data>>=1)&1; + pinfo->did_sell = (data>>=1)&1; + pinfo->was_happy = (data>>=1)&1; + pinfo->airlift = (data>>=1)&1; + pinfo->diplomat_investigate = (data>>=1)&1; + pinfo->changed_from_is_unit = (data>>=1)&1; + + + if( flags & FLGSCI_citymap ) + { + dio_get_city_map(&din, (char*)pinfo->city_map, sizeof(pinfo->city_map)); + memcpy(&cce->city_map, &pinfo->city_map, sizeof(cce->city_map)); + } + else + memcpy(&pinfo->city_map, &cce->city_map, sizeof(pinfo->city_map)); + + if( flags & FLGSCI_improvements ) + { + dio_get_bit_string(&din, (char*)pinfo->improvements, sizeof(pinfo->improvements)); + strncpy( (char*)&cce->improvements, (char*)&pinfo->improvements, strlen(pinfo->improvements)+1 ); + } + else + strncpy( (char*)&pinfo->improvements, (char*)&cce->improvements, strlen(cce->improvements)+1); + + if( flags & FLGSCI_trade ) + { + for(data=0; data < NUM_TRADEROUTES; data++) { + /* This is the last entry in the packet. It would be possible + to only send non-zero trade routes. This isnt done yet. Probably + not worth the effort. --yon + + if (dio_input_remaining(&din) < 3) + break; + */ + dio_get_uint16(&din, &pinfo->trade[data]); + dio_get_uint8(&din, &pinfo->trade_value[data]); + } + /* for(;data<4;data++) pinfo->trade_value[data] = pinfo->trade[data] = 0; + */ + for(data=0;data<4;data++) { + cce->trade[data] = pinfo->trade[data]; + cce->trade_value[data] = pinfo->trade_value[data]; + } + } + else + { + for(data=0;data<4;data++) { + pinfo->trade[data] = cce->trade[data]; + pinfo->trade_value[data] = cce->trade_value[data]; + } + } +#ifdef CONFIG_SCI_PACKETS_CRC + if( flags2 & FLGSCI_2_crc) { + uLong received_crc, adler; + adler= adler32(0L, Z_NULL, 0); + dio_get_uint32(&din, (int*)&received_crc); + clr_str(pinfo->name); + clr_str(pinfo->worklist.name); + clr_str(pinfo->improvements); + // pinfo->flags = flags; + adler = adler32(adler, (char*)pinfo, sizeof(*pinfo)); + if( adler != received_crc ) + freelog(LOG_ERROR, "SCI CRC doesnt match, check your bits"); + else + freelog(LOG_ERROR, "SCI CRC matches"); + } +#endif + RECEIVE_PACKET_END(pinfo); +} + +#endif /* CONFIG_SCI_PACKETS */ + /************************************************************************** ... **************************************************************************/ diff -dBbH --exclude-from=vanilla/diff_ignore --exclude-from=vanilla/.cvsignore --exclude Freeciv.h --exclude aaa.h --exclude 'rcstart*' --exclude 'short*' --exclude='civgame*.sav.gz' --exclude='*log*' --exclude=bb.out --exclude=aclocal.m4 --exclude='gmon*' --exclude='*.tgz' --exclude='*diff*' --exclude='*.rej' --exclude='.#*' --exclude=.deps --exclude=POTFILES --exclude=stamp-h --exclude='config*' --exclude=undep.sh --exclude='*.o' --exclude='*.orig' --exclude='*~' --exclude=Makefile --exclude=Makefile.in --exclude=CVS -pNur vanilla/common/packets.h compress/common/packets.h --- vanilla/common/packets.h Sat Oct 19 06:02:07 2002 +++ compress/common/packets.h Sun Nov 3 17:10:27 2002 @@ -128,9 +128,29 @@ enum packet_type { PACKET_SELECT_NATION_OK, PACKET_FREEZE_HINT, PACKET_THAW_HINT, +#ifdef CONFIG_COMPRESSED_NETWORK + PACKET_START_COMPRESSION, +#endif +#ifdef CONFIG_SPI_PACKETS + PACKET_SHORT_PLAYER_INFO, +#endif +#ifdef CONFIG_STI_PACKETS + PACKET_SHORT_TILE_INFO, +#endif +#ifdef CONFIG_SCI_PACKETS + PACKET_SHORT_CITY_INFO, +#endif +#ifdef CONFIG_SUI_PACKETS + PACKET_SHORT_UNIT_INFO, +#endif +#ifdef CONFIG_SGI_PACKETS + PACKET_SHORT_GAME_INFO, +#endif PACKET_LAST /* leave this last */ }; +extern char *packet_names[PACKET_LAST+1]; + enum report_type { REPORT_WONDERS_OF_THE_WORLD, REPORT_TOP_5_CITIES, @@ -289,6 +309,30 @@ struct packet_move_unit { }; +#ifdef CONFIG_SUI_PACKETS +#define FLGSUI_owner 0x0001 +#define FLGSUI_pack 0x0002 +#define FLGSUI_x 0x0004 +#define FLGSUI_y 0x0008 +#define FLGSUI_homecity 0x0010 +#define FLGSUI_type 0x0020 +#define FLGSUI_movesleft 0x0040 +#define FLGSUI_hp 0x0080 +#define FLGSUI_upkeep 0x0100 +#define FLGSUI_upkeep_gold 0x0200 +#define FLGSUI_upkeep_food 0x0400 +#define FLGSUI_unhappiness 0x0800 +#define FLGSUI_activity 0x1000 +#define FLGSUI_activity_count 0x2000 +#define FLGSUI_goto_dest_x 0x4000 +#define FLGSUI_goto_dest_y 0x8000 +#define FLGSUI_activity_target 0x10000 +#define FLGSUI_packet_use 0x20000 +#define FLGSUI_info_city_id 0x40000 +#define FLGSUI_serial_num 0x80000 +#define FLGSUI_fuel 0x100000 +#endif + /********************************************************* *********************************************************/ @@ -323,6 +367,48 @@ struct packet_unit_info { (not used by UNIT_INFO_IDENTITY) */ }; +//flags bit values +#define FLGSCI_ppl 0x1 +#define FLGSCI_shield_stock 0x2 +#define FLGSCI_before_change_shields 0x4 +#define FLGSCI_food_stock 0x8 +#define FLGSCI_flags1 0x10 +#define FLGSCI_science_total 0x20 +#define FLGSCI_currently_building 0x40 +#define FLGSCI_citymap 0x80 +#define FLGSCI_ppl_taxman 0x100 +#define FLGSCI_changed_from_id 0x200 +#define FLGSCI_food_surplus 0x400 +#define FLGSCI_shield_prod 0x800 +#define FLGSCI_shield_surplus 0x1000 +#define FLGSCI_trade_prod 0x2000 +#define FLGSCI_tile_trade 0x4000 +#define FLGSCI_tax_total 0x8000 +#define FLGSCI_city_options 0x10000 +#define FLGSCI_ppl_scientist 0x20000 +#define FLGSCI_size 0x40000 +#define FLGSCI_flags2 0x80000 +#define FLGSCI_improvements 0x100000 +#define FLGSCI_pollution 0x200000 +#define FLGSCI_trade 0x400000 +#define FLGSCI_turn_last_built 0x800000 +#define FLGSCI_turn_changed_target 0x1000000 +#define FLGSCI_food_prod 0x2000000 +#define FLGSCI_ppl_elvis 0x4000000 +#define FLGSCI_disbanded_shields 0x8000000 +#define FLGSCI_caravan_shields 0x10000000 +#define FLGSCI_worklist 0x20000000 +#define FLGSCI_corruption 0x40000000 +#define FLGSCI_luxury_total 0x80000000 + +//flags2 bit values +#define FLGSCI_2_x 0x1 +#define FLGSCI_2_y 0x2 +#define FLGSCI_2_owner 0x4 +#define FLGSCI_2_turn_founded 0x8 +#define FLGSCI_2_name 0x10 +#define FLGSCI_2_crc 0x20 + /********************************************************* ... @@ -369,9 +455,33 @@ struct packet_city_info { bool diplomat_investigate; int city_options; int turn_founded; + // int flags; }; +#define FLGSPI_name 0x1 +#define FLGSPI_government 0x2 +#define FLGSPI_embassy 0x4 +#define FLGSPI_city_style 0x8 +#define FLGSPI_nation 0x10 +#define FLGSPI_nturns_idle 0x20 +#define FLGSPI_combined 0x40 +#define FLGSPI_reputation 0x80 +#define FLGSPI_inventions 0x100 +#define FLGSPI_gold 0x200 +#define FLGSPI_tax 0x400 +#define FLGSPI_science 0x800 +#define FLGSPI_luxury 0x1000 +#define FLGSPI_bulbs_researched 0x2000 +#define FLGSPI_techs_researched 0x4000 +#define FLGSPI_researching 0x8000 +#define FLGSPI_future_tech 0x10000 +#define FLGSPI_gives_shared_vision 0x20000 +#define FLGSPI_tech_goal 0x40000 +#define FLGSPI_diplstates 0x80000 +#define FLGSPI_barbarian_type 0x100000 + + struct packet_short_city { int id; /* uint16 */ int owner; /* uint8 */ @@ -481,6 +591,9 @@ struct packet_player_info { bool ai; int barbarian_type; unsigned int gives_shared_vision; +#ifdef CONFIG_SPI_PACKETS + unsigned int flags; /* to be used by short_player_info */ +#endif }; /************************************************************************** @@ -834,6 +947,38 @@ struct packet_game_info { int seconds_to_turndone; }; +#ifdef CONFIG_SGI_PACKETS +#define FLGSGI_gold 0x0001 +#define FLGSGI_tech 0x0002 +#define FLGSGI_researchcost 0x0004 +#define FLGSGI_skill_level 0x0008 +#define FLGSGI_timeout 0x0010 +#define FLGSGI_end_year 0x0020 +#define FLGSGI_year 0x0040 +#define FLGSGI_min_players 0x0080 +#define FLGSGI_max_players 0x0100 +#define FLGSGI_nplayers 0x0200 +#define FLGSGI_player_idx 0x0400 +#define FLGSGI_globalwarming 0x0800 +#define FLGSGI_heating 0x1000 +#define FLGSGI_nuclearwinter 0x2000 +#define FLGSGI_cooling 0x4000 +#define FLGSGI_cityfactor 0x8000 +#define FLGSGI_diplcost 0x10000 +#define FLGSGI_freecost 0x20000 +#define FLGSGI_conquercost 0x40000 +#define FLGSGI_unhappysize 0x80000 +#define FLGSGI_angrycitizen 0x100000 +#define FLGSGI_techpenalty 0x200000 +#define FLGSGI_foodbox 0x400000 +#define FLGSGI_civstyle 0x800000 +#define FLGSGI_spacerace 0x1000000 +#define FLGSGI_seconds_to_turndone 0x2000000 +#define FLGSGI_turn 0x4000000 +#define FLGSGI_global_advances 0x8000000 +#define FLGSGI_global_wonders 0x10000000 +#endif + /********************************************************* ... *********************************************************/ @@ -929,6 +1074,12 @@ int send_packet_tile_info(struct connect const struct packet_tile_info *pinfo); struct packet_tile_info *receive_packet_tile_info(struct connection *pc); +#ifdef CONFIG_STI_PACKETS +int send_packet_short_tile_info(struct connection *pc, + const struct packet_tile_info *pinfo); +struct packet_tile_info *receive_packet_short_tile_info(struct connection *pc); +#endif + int send_packet_map_info(struct connection *pc, const struct packet_map_info *pinfo); struct packet_map_info *receive_packet_map_info(struct connection *pc); @@ -937,11 +1088,22 @@ int send_packet_game_info(struct connect const struct packet_game_info *pinfo); struct packet_game_info *receive_packet_game_info(struct connection *pc); +#ifdef CONFIG_SGI_PACKETS +struct packet_game_info *receive_packet_short_game_info(struct connection *pc); +int send_packet_short_game_info(struct connection *pc, + const struct packet_game_info *pinfo); +#endif struct packet_player_info *receive_packet_player_info(struct connection *pc); int send_packet_player_info(struct connection *pc, const struct packet_player_info *pinfo); +#ifdef CONFIG_SPI_PACKETS +struct packet_player_info *receive_packet_short_player_info(struct connection *pc); +int send_packet_short_player_info(struct connection *pc, + const struct packet_player_info *pinfo); +#endif + struct packet_conn_info *receive_packet_conn_info(struct connection *pc); int send_packet_conn_info(struct connection *pc, const struct packet_conn_info *pinfo); @@ -1093,6 +1255,17 @@ int send_packet_sabotage_list(struct con struct packet_sabotage_list * receive_packet_sabotage_list(struct connection *pc); +#ifdef CONFIG_SCI_PACKETS +struct packet_city_info *receive_packet_short_city_info(struct connection *pc); +int send_packet_short_city_info(struct connection *pc, + const struct packet_city_info *pinfo); +#endif +#ifdef CONFIG_SUI_PACKETS +struct packet_unit_info *receive_packet_short_unit_info(struct connection *pc); +int send_packet_short_unit_info(struct connection *pc, + const struct packet_unit_info *pinfo); +#endif + void *get_packet_from_connection(struct connection *pc, enum packet_type *ptype, bool *presult); void remove_packet_from_buffer(struct socket_packet_buffer *buffer); diff -dBbH --exclude-from=vanilla/diff_ignore --exclude-from=vanilla/.cvsignore --exclude Freeciv.h --exclude aaa.h --exclude 'rcstart*' --exclude 'short*' --exclude='civgame*.sav.gz' --exclude='*log*' --exclude=bb.out --exclude=aclocal.m4 --exclude='gmon*' --exclude='*.tgz' --exclude='*diff*' --exclude='*.rej' --exclude='.#*' --exclude=.deps --exclude=POTFILES --exclude=stamp-h --exclude='config*' --exclude=undep.sh --exclude='*.o' --exclude='*.orig' --exclude='*~' --exclude=Makefile --exclude=Makefile.in --exclude=CVS -pNur vanilla/common/unittype.c compress/common/unittype.c --- vanilla/common/unittype.c Wed Aug 7 13:21:49 2002 +++ compress/common/unittype.c Fri Oct 18 16:32:44 2002 @@ -89,14 +89,6 @@ struct unit_type *get_unit_type(Unit_Typ /************************************************************************** ... **************************************************************************/ -struct unit_type *unit_type(struct unit *punit) -{ - return get_unit_type(punit->type); -} - -/************************************************************************** -... -**************************************************************************/ bool is_ground_unittype(Unit_Type_id id) { return (unit_types[id].move_type == LAND_MOVING); @@ -235,6 +227,15 @@ const char *get_unit_name(Unit_Type_id i /************************************************************************** ... +**************************************************************************/ +struct unit_type *unit_type(struct unit *punit) +{ + return get_unit_type(punit->type); +} + + +/************************************************************************** +... **************************************************************************/ const char *unit_class_name(Unit_Class_id id) { diff -dBbH --exclude-from=vanilla/diff_ignore --exclude-from=vanilla/.cvsignore --exclude Freeciv.h --exclude aaa.h --exclude 'rcstart*' --exclude 'short*' --exclude='civgame*.sav.gz' --exclude='*log*' --exclude=bb.out --exclude=aclocal.m4 --exclude='gmon*' --exclude='*.tgz' --exclude='*diff*' --exclude='*.rej' --exclude='.#*' --exclude=.deps --exclude=POTFILES --exclude=stamp-h --exclude='config*' --exclude=undep.sh --exclude='*.o' --exclude='*.orig' --exclude='*~' --exclude=Makefile --exclude=Makefile.in --exclude=CVS -pNur vanilla/server/gamehand.c compress/server/gamehand.c --- vanilla/server/gamehand.c Fri Sep 27 14:32:46 2002 +++ compress/server/gamehand.c Mon Nov 4 13:10:08 2002 @@ -157,6 +157,11 @@ void init_new_game(void) **************************************************************************/ void send_start_turn_to_clients(void) { +#ifdef CONFIG_COMPRESSED_NETWORK + /* Between before_year and this we may not flush the compression state, + thus getting better compression */ + need_not_flush_compression = FALSE; +#endif lsend_packet_generic_empty(&game.est_connections, PACKET_START_TURN); } diff -dBbH --exclude-from=vanilla/diff_ignore --exclude-from=vanilla/.cvsignore --exclude Freeciv.h --exclude aaa.h --exclude 'rcstart*' --exclude 'short*' --exclude='civgame*.sav.gz' --exclude='*log*' --exclude=bb.out --exclude=aclocal.m4 --exclude='gmon*' --exclude='*.tgz' --exclude='*diff*' --exclude='*.rej' --exclude='.#*' --exclude=.deps --exclude=POTFILES --exclude=stamp-h --exclude='config*' --exclude=undep.sh --exclude='*.o' --exclude='*.orig' --exclude='*~' --exclude=Makefile --exclude=Makefile.in --exclude=CVS -pNur vanilla/server/maphand.c compress/server/maphand.c --- vanilla/server/maphand.c Sat Sep 28 03:36:24 2002 +++ compress/server/maphand.c Mon Nov 4 13:10:27 2002 @@ -815,9 +815,11 @@ static int map_get_seen(int x, int y, st void map_change_seen(int x, int y, struct player *pplayer, int change) { map_get_player_tile(x, y, pplayer)->seen += change; - freelog(LOG_DEBUG, "%d,%d, p: %d, change %d, result %d\n", x, y, + /* + freelog(LOG_DEBUG, "%d,%d, p: %d, change %d, result %d", x, y, pplayer->player_no, change, map_get_player_tile(x, y, pplayer)->seen); + */ } /*************************************************************** diff -dBbH --exclude-from=vanilla/diff_ignore --exclude-from=vanilla/.cvsignore --exclude Freeciv.h --exclude aaa.h --exclude 'rcstart*' --exclude 'short*' --exclude='civgame*.sav.gz' --exclude='*log*' --exclude=bb.out --exclude=aclocal.m4 --exclude='gmon*' --exclude='*.tgz' --exclude='*diff*' --exclude='*.rej' --exclude='.#*' --exclude=.deps --exclude=POTFILES --exclude=stamp-h --exclude='config*' --exclude=undep.sh --exclude='*.o' --exclude='*.orig' --exclude='*~' --exclude=Makefile --exclude=Makefile.in --exclude=CVS -pNur vanilla/server/sernet.c compress/server/sernet.c --- vanilla/server/sernet.c Fri Oct 18 11:58:49 2002 +++ compress/server/sernet.c Mon Nov 4 13:43:51 2002 @@ -75,7 +75,8 @@ #include "meta.h" #include "srv_main.h" #include "stdinhand.h" - +#include "connection.h" +#include "hash.h" #include "sernet.h" static struct connection connections[MAX_NUM_CONNECTIONS]; @@ -178,6 +179,64 @@ void close_connection(struct connection free_socket_packet_buffer(pconn->send_buffer); pconn->buffer = NULL; pconn->send_buffer = NULL; +#ifdef CONFIG_COMPRESSED_NETWORK + free_socket_packet_buffer(pconn->compress_tmp_rx_buffer); + pconn->compress_tmp_rx_buffer = NULL; + pconn->need_not_flush_compression = 0; + if ( NULL != pconn->compress_rx_ctx ) { + inflateEnd( pconn->compress_rx_ctx ); + free( pconn->compress_rx_ctx ); + pconn->compress_rx_ctx = NULL ; + } + if ( NULL != pconn->compress_tx_ctx ) { + deflateEnd( pconn->compress_tx_ctx ); + free( pconn->compress_tx_ctx ); + pconn->compress_tx_ctx = NULL ; + } +#endif + /*YYY*/ +#ifdef CONFIG_SPI_PACKETS + memset(&pconn->pinfo_cache, 0, sizeof(pconn->pinfo_cache) ); + pconn->use_spi = FALSE; +#endif + +#ifdef CONFIG_STI_PACKETS + if(pconn->map_cache) + { + free(pconn->map_cache); + pconn->map_cache = NULL; + } + pconn->use_sti = FALSE; +#endif + +#ifdef CONFIG_SCI_PACKETS + if(pconn->city_cache ) + { + // struct city_cache_entry* cce; + while (hash_num_entries(pconn->city_cache) > 0) + free( hash_delete_entry(pconn->city_cache, hash_key_by_number(pconn->city_cache, 0)) ); + } + pconn->use_sci = FALSE; +#endif + +#ifdef CONFIG_SUI_PACKETS + if(pconn->unit_cache ) + { + while (hash_num_entries(pconn->unit_cache) > 0) + free( hash_delete_entry(pconn->unit_cache, hash_key_by_number(pconn->unit_cache, 0)) ); + } + pconn->use_sui = FALSE; +#endif + +#ifdef CONFIG_SGI_PACKETS + if(pconn->game_info_cache ) { + freelog(LOG_ERROR, "Destroying game info cache "); + free(pconn->game_info_cache); + pconn->use_sgi = FALSE; + pconn->game_info_cache = NULL; + } + pconn->use_sgi = FALSE; +#endif } /***************************************************************************** @@ -698,6 +757,9 @@ static int server_accept_connection(int pconn->player = NULL; pconn->buffer = new_socket_packet_buffer(); pconn->send_buffer = new_socket_packet_buffer(); +#ifdef CONFIG_COMPRESSED_NETWORK + pconn->compress_tmp_rx_buffer = new_socket_packet_buffer(); +#endif pconn->last_write = 0; pconn->ponged = TRUE; pconn->first_packet = TRUE; @@ -710,6 +772,35 @@ static int server_accept_connection(int pconn->server.last_request_id_seen = 0; pconn->incoming_packet_notify = NULL; pconn->outgoing_packet_notify = NULL; + /* YYY */ +#ifdef CONFIG_SCI_PACKETS + if ( pconn->city_cache == NULL ) + pconn->city_cache = hash_new_nentries(&hash_fval_keyval, &hash_fcmp_keyval, 311) ; +#endif + +#ifdef CONFIG_SUI_PACKETS + if( pconn->unit_cache == NULL ) + pconn->unit_cache = hash_new_nentries(&hash_fval_keyval, &hash_fcmp_keyval, 911) ; +#endif + +#ifdef CONFIG_STI_PACKETS + /* the array gets allocated when the map size is known */ + if( pconn->map_cache != NULL ) { + free(pconn->map_cache); + pconn->map_cache = NULL; + } +#endif + +#ifdef CONFIG_SPI_PACKETS + // nothing to do, static per structure array + memset( pconn->pinfo_cache, 0, sizeof(pconn->pinfo_cache) ); +#endif +#ifdef CONFIG_SGI_PACKETS + if( NULL != pconn->game_info_cache ) { + free(pconn->game_info_cache); + pconn->game_info_cache = NULL; + } +#endif sz_strlcpy(pconn->name, makeup_connection_name(&pconn->id)); sz_strlcpy(pconn->addr, @@ -804,6 +895,12 @@ static void start_processing_request(str assert(pconn->server.currently_processed_request_id == 0); freelog(LOG_DEBUG, "start processing packet %d from connection %d", request_id, pconn->id); +#ifdef CONFIG_COMPRESSED_NETWORK + if( NULL != pconn->compress_tx_ctx) { + assert(pconn->need_not_flush_compression == 0); + pconn->need_not_flush_compression = 1; + } +#endif send_packet_generic_empty(pconn, PACKET_PROCESSING_STARTED); pconn->server.currently_processed_request_id = request_id; } @@ -816,6 +913,12 @@ static void finish_processing_request(st assert(pconn->server.currently_processed_request_id); freelog(LOG_DEBUG, "finish processing packet %d from connection %d", pconn->server.currently_processed_request_id, pconn->id); +#ifdef CONFIG_COMPRESSED_NETWORK + if( NULL != pconn->compress_tx_ctx) { + assert(pconn->need_not_flush_compression == 1); + pconn->need_not_flush_compression = 2; + } +#endif send_packet_generic_empty(pconn, PACKET_PROCESSING_FINISHED); pconn->server.currently_processed_request_id = 0; } diff -dBbH --exclude-from=vanilla/diff_ignore --exclude-from=vanilla/.cvsignore --exclude Freeciv.h --exclude aaa.h --exclude 'rcstart*' --exclude 'short*' --exclude='civgame*.sav.gz' --exclude='*log*' --exclude=bb.out --exclude=aclocal.m4 --exclude='gmon*' --exclude='*.tgz' --exclude='*diff*' --exclude='*.rej' --exclude='.#*' --exclude=.deps --exclude=POTFILES --exclude=stamp-h --exclude='config*' --exclude=undep.sh --exclude='*.o' --exclude='*.orig' --exclude='*~' --exclude=Makefile --exclude=Makefile.in --exclude=CVS -pNur vanilla/server/srv_main.c compress/server/srv_main.c --- vanilla/server/srv_main.c Fri Oct 18 11:58:49 2002 +++ compress/server/srv_main.c Mon Nov 4 13:47:21 2002 @@ -93,6 +93,10 @@ #include "aidata.h" #include "aihand.h" +#if defined(CONFIG_SUI_PACKETS) || defined(CONFIG_SCI_PACKETS) +#include "hash.h" +#endif + #include "srv_main.h" @@ -148,6 +152,11 @@ static unsigned char used_ids[8192]={0}; /* server initialized flag */ static bool has_been_srv_init = FALSE; +#ifdef CONFIG_COMPRESSED_NETWORK +/* global compression hint */ +bool need_not_flush_compression = FALSE; +#endif + /************************************************************************** ... **************************************************************************/ @@ -353,6 +362,12 @@ static void update_diplomatics(void) **************************************************************************/ static void before_end_year(void) { +#ifdef CONFIG_COMPRESSED_NETWORK + /* Between this and send_start_turn_to_clients we may not flush + the compression state, thus getting better compression */ + need_not_flush_compression = TRUE; +#endif + lsend_packet_generic_empty(&game.est_connections, PACKET_BEFORE_NEW_YEAR); } @@ -1047,6 +1062,74 @@ static void join_game_accept(struct conn my_snprintf(packet.message, sizeof(packet.message), "%s %s.", (rejoin?"Welcome back":"Welcome"), pplayer->name); send_packet_join_game_reply(pconn, &packet); + +#ifdef CONFIG_SPI_PACKETS + if ( has_capability("packet_spi", pconn->capability)) { + freelog(LOG_ERROR, "Server sending SPI packets."); + pconn->use_spi = TRUE; + } +#endif + +#ifdef CONFIG_STI_PACKETS + if ( has_capability("packet_sti", pconn->capability)) { + freelog(LOG_ERROR, "Server sending STI packets."); + pconn->use_sti = TRUE; + // if( pconn->map_cache == NULL ) + assert( pconn->map_cache == NULL ) ; + /* first use, allocate map buffer, size is known now */ + pconn->map_cache = fc_malloc( map.xsize * map.ysize * + sizeof(struct map_cache_entry)); + memset( pconn->map_cache, 0, map.xsize * map.ysize * + sizeof(struct map_cache_entry)); + + } +#endif + +#ifdef CONFIG_SGI_PACKETS + if ( has_capability("packet_sgi", pconn->capability)) { + freelog(LOG_ERROR, "Server sending SGI packets."); + pconn->use_sgi = TRUE; + pconn->game_info_cache = fc_malloc(sizeof(struct packet_game_info)); + memset(pconn->game_info_cache, 0, sizeof(*pconn->game_info_cache)); + } +#endif + +#ifdef CONFIG_SCI_PACKETS + if ( has_capability("packet_sci", pconn->capability)) { + freelog(LOG_ERROR, "Server sending SCI packets."); + pconn->use_sci = TRUE; + if(pconn->city_cache == NULL) + pconn->city_cache = hash_new_nentries(&hash_fval_keyval,&hash_fcmp_keyval,311) ; + } +#endif + +#ifdef CONFIG_SUI_PACKETS + if ( has_capability("packet_sui", pconn->capability)) { + freelog(LOG_ERROR, "Server sending SUI packets."); + pconn->use_sui = TRUE; + if(pconn->unit_cache == NULL) + pconn->unit_cache = hash_new_nentries(&hash_fval_keyval,&hash_fcmp_keyval,911) ; + } +#endif + +#ifdef CONFIG_COMPRESSED_NETWORK + /* If client has compressed network capability, all communications + after this packet will be compressed */ + if ( has_capability("compressed_network", pconn->capability)) { + freelog(LOG_ERROR, _("%s (%s) is getting his traffic compressed"), + pconn->name, pplayer->name); + pconn->need_not_flush_compression = 1; + /* finish_processing will reset the compression hint */ + pconn->compress_tx_ctx = fc_malloc( sizeof(struct z_stream_s)); + pconn->compress_tx_ctx->zalloc = Z_NULL; + pconn->compress_tx_ctx->zfree = Z_NULL; + pconn->compress_tx_ctx->opaque = NULL; + deflateInit(pconn->compress_tx_ctx, 9); + } else + freelog(LOG_ERROR, _("%s (%s) is NOT getting his traffic compressed"), + pconn->name, pplayer->name); +#endif + pconn->established = TRUE; conn_list_insert_back(&game.est_connections, pconn); conn_list_insert_back(&game.game_connections, pconn); @@ -1353,6 +1436,11 @@ static bool handle_request_join_game(str || (pplayer->is_connected && (*allow != '*'))) { pconn->observer = TRUE; } +#ifdef CONFIG_COMPRESSED_NETWORK +/* This would affect all players, but this is not multithreaded. */ +/* XXX only change pconn->need_... ? */ + need_not_flush_compression = TRUE; +#endif associate_player_connection(pplayer, pconn); join_game_accept(pconn, TRUE); introduce_game_to_connection(pconn); @@ -1369,6 +1457,9 @@ static bool handle_request_join_game(str if (game.auto_ai_toggle && pplayer->ai.control) { toggle_ai_player_direct(NULL, pplayer); } +#ifdef CONFIG_COMPRESSED_NETWORK + need_not_flush_compression = FALSE; +#endif return TRUE; } @@ -1412,8 +1503,20 @@ void lost_connection_to_client(struct co struct player *pplayer = pconn->player; const char *desc = conn_description(pconn); - freelog(LOG_NORMAL, _("Lost connection: %s."), desc); +#ifdef CONFIG_COMPRESSED_NETWORK + if ( NULL != pconn->compress_tx_ctx ) { + struct z_stream_s *ctx = pconn->compress_tx_ctx; + freelog(LOG_ERROR, _("Lost connection: %s.(%ld/%ld %d%%)"), + desc, ctx->total_out, ctx->total_in, + (int)(100*ctx->total_out/ctx->total_in) ); + } + else + freelog(LOG_NORMAL, _("Lost connection: %s."), desc); + // freelog(LOG_NORMAL, _("Lost connection: %s. (%ld)"), desc, pconn->); +#else + freelog(LOG_NORMAL, _("Lost connection: %s."), desc); +#endif /* _Must_ avoid sending to pconn, in case pconn connection is * really lost (as opposed to server shutting it down) which would * trigger an error on send and recurse back to here. @@ -1868,8 +1971,14 @@ void srv_main(void) nations_used = fc_calloc(game.playable_nation_count, sizeof(int)); main_start_players: +#ifdef CONFIG_COMPRESSED_NETWORK + need_not_flush_compression = TRUE; +#endif send_rulesets(&game.est_connections); +#ifdef CONFIG_COMPRESSED_NETWORK + need_not_flush_compression = FALSE; +#endif num_nations_avail = game.playable_nation_count; for(i=0; i