diff -ruN -X freeciv/diff_ignore freeciv/client/civclient.c freeciv.mod/client/civclient.c --- freeciv/client/civclient.c Sun Jan 7 14:09:56 2001 +++ freeciv.mod/client/civclient.c Mon Jan 15 15:36:27 2001 @@ -360,7 +360,12 @@ case PACKET_CONN_INFO: handle_conn_info((struct packet_conn_info *)packet); break; - + + case PACKET_ATTRIBUTE_CHUNK: + handle_player_attribute_chunk((struct packet_attribute_chunk *) + packet); + break; + default: freelog(LOG_ERROR, "Received unknown packet (type %d) from server!", type); /* Old clients (<= some 1.11.5-devel, capstr +1.11) used to exit() @@ -512,3 +517,15 @@ void dealloc_id(int id); /* double kludge (suppress a possible warning) */ void dealloc_id(int id) { }/* kludge */ + +/************************************************************************** +.. +**************************************************************************/ +void send_attribute_block_request() +{ + struct packet_player_request packet; + + packet.attribute_block = 1; + send_packet_player_request(&aconnection, &packet, + PACKET_PLAYER_ATTRIBUTE_BLOCK); +} diff -ruN -X freeciv/diff_ignore freeciv/client/civclient.h freeciv.mod/client/civclient.h --- freeciv/client/civclient.h Wed Aug 9 15:11:38 2000 +++ freeciv.mod/client/civclient.h Mon Jan 15 13:05:36 2001 @@ -21,6 +21,7 @@ void send_unit_info(struct unit *punit); void send_move_unit(struct unit *punit); void send_report_request(enum report_type type); +void send_attribute_block_request(); void user_ended_turn(void); diff -ruN -X freeciv/diff_ignore freeciv/client/packhand.c freeciv.mod/client/packhand.c --- freeciv/client/packhand.c Wed Jan 10 22:24:06 2001 +++ freeciv.mod/client/packhand.c Mon Jan 15 16:17:56 2001 @@ -223,6 +223,8 @@ if(get_client_state()==CLIENT_GAME_RUNNING_STATE) { struct city *pcity; struct unit *punit; + + send_attribute_block_request(); refresh_overview_canvas(); refresh_overview_viewrect(); enable_turn_done_button(); @@ -2162,5 +2164,18 @@ pcity->improvements[i] = (packet->improvements[i]=='1') ? 1 : 0; popup_sabotage_dialog(pcity); + } +} + +/************************************************************************** +... +**************************************************************************/ +void handle_player_attribute_chunk(struct packet_attribute_chunk *chunk) +{ + generic_handle_attribute_chunk(game.player_ptr, chunk); + + if (chunk->offset + chunk->chunk_length == chunk->total_length) { + /* We successful received the last chunk. The attribute block is + now complete. */ } } diff -ruN -X freeciv/diff_ignore freeciv/client/packhand.h freeciv.mod/client/packhand.h --- freeciv/client/packhand.h Sun Aug 27 08:57:22 2000 +++ freeciv.mod/client/packhand.h Mon Jan 15 13:00:36 2001 @@ -58,5 +58,6 @@ void handle_ruleset_game(struct packet_ruleset_game *packet); void handle_diplomat_action(struct packet_diplomat_action *packet); void handle_sabotage_list(struct packet_sabotage_list *packet); +void handle_player_attribute_chunk(struct packet_attribute_chunk *packet); #endif /* FC__PACKHAND_H */ diff -ruN -X freeciv/diff_ignore freeciv/common/capstr.c freeciv.mod/common/capstr.c --- freeciv/common/capstr.c Sat Oct 28 00:20:07 2000 +++ freeciv.mod/common/capstr.c Mon Jan 15 11:23:58 2001 @@ -73,7 +73,8 @@ #define CAPABILITY "+1.11 diplomat_investigate_fix production_change_fix" \ " game_ruleset nuclear_fallout land_channel_requirement event_wonder_obsolete" \ " event00_fix conn_info gen_impr_oversights diplo_move_city packet_short_city" \ -" indef_impr_types worklist_true_ids shared_vision activity_patrol" +" indef_impr_types worklist_true_ids shared_vision activity_patrol" \ +" attributes" /* "+1.11" is protocol for 1.11.0 stable release. @@ -129,6 +130,8 @@ "activity_patrol" is the patrol activity and the ability to send a goto route from the client to the server (for both goto and patrol activities). + + "attributes" is the ability to request and transfer attribute blocks. */ void init_our_capability(void) diff -ruN -X freeciv/diff_ignore freeciv/common/game.c freeciv.mod/common/game.c --- freeciv/common/game.c Thu Jan 4 01:49:04 2001 +++ freeciv.mod/common/game.c Mon Jan 15 11:12:26 2001 @@ -926,6 +926,11 @@ { struct player *pplayer=&game.players[plrno]; + if (pplayer->attribute_block.data != NULL) { + free(pplayer->attribute_block.data); + pplayer->attribute_block.data = NULL; + } + unit_list_iterate(pplayer->units, punit) game_remove_unit(punit->id); unit_list_iterate_end; diff -ruN -X freeciv/diff_ignore freeciv/common/packets.c freeciv.mod/common/packets.c --- freeciv/common/packets.c Fri Dec 15 18:56:06 2000 +++ freeciv.mod/common/packets.c Mon Jan 15 15:32:02 2001 @@ -284,6 +284,7 @@ case PACKET_PLAYER_RESEARCH: case PACKET_PLAYER_TECH_GOAL: case PACKET_PLAYER_WORKLIST: + case PACKET_PLAYER_ATTRIBUTE_BLOCK: return receive_packet_player_request(pc); case PACKET_UNIT_BUILD_CITY: @@ -363,6 +364,9 @@ case PACKET_PATROL_ROUTE: return receive_packet_goto_route(pc); + case PACKET_ATTRIBUTE_CHUNK: + return receive_packet_attribute_chunk(pc); + default: freelog(LOG_ERROR, "unknown packet type %d received from %s", type, conn_description(pc)); @@ -1519,12 +1523,16 @@ may want to remove the 'pc' argument (?) */ cptr=put_worklist(cptr, &packet->worklist, pc); cptr=put_uint8(cptr, packet->wl_idx); + + if (pc && has_capability("attributes", pc->capability)) { + cptr = put_uint8(cptr, packet->attribute_block); + } + put_uint16(buffer, cptr-buffer); return send_connection_data(pc, buffer, cptr-buffer); } - /************************************************************************* ... **************************************************************************/ @@ -1546,6 +1554,10 @@ may want to remove the 'pc' argument (?) */ iget_worklist(&iter, &preq->worklist, pc); iget_uint8(&iter, &preq->wl_idx); + if (pc && has_capability("attributes", pc->capability)) + iget_uint8(&iter, &preq->attribute_block); + else + preq->attribute_block = 0; pack_iter_end(&iter, pc); remove_packet_from_buffer(pc->buffer); @@ -4189,4 +4201,126 @@ freelog(LOG_ERROR, "invalid type in receive_packet_goto_route()"); return NULL; } +} + +/************************************************************************** +... +**************************************************************************/ +int send_packet_attribute_chunk(struct connection *pc, + struct packet_attribute_chunk *packet) +{ + unsigned char buffer[MAX_LEN_PACKET], *cptr; + + assert(packet->total_length > 0 + && packet->total_length < MAX_ATTRIBUTE_BLOCK); + /* 500 bytes header, just to be sure */ + assert(packet->chunk_length > 0 + && packet->chunk_length < MAX_LEN_PACKET - 500); + assert(packet->chunk_length <= packet->total_length); + assert(packet->offset >= 0 && packet->offset < packet->total_length); + + cptr = put_uint8(buffer + 2, PACKET_ATTRIBUTE_CHUNK); + + cptr = put_uint32(cptr, packet->offset); + cptr = put_uint32(cptr, packet->total_length); + cptr = put_uint32(cptr, packet->chunk_length); + + memcpy(cptr, packet->data, packet->chunk_length); + cptr+=packet->chunk_length; + + put_uint16(buffer, cptr - buffer); + send_connection_data(pc, buffer, cptr - buffer); + + return 0; +} +/************************************************************************** +.. +**************************************************************************/ +struct packet_attribute_chunk *receive_packet_attribute_chunk(struct + connection + *pc) +{ + struct pack_iter iter; + struct packet_attribute_chunk *packet = + fc_malloc(sizeof(struct packet_attribute_chunk)); + + pack_iter_init(&iter, pc); + + iget_uint32(&iter, &packet->offset); + iget_uint32(&iter, &packet->total_length); + iget_uint32(&iter, &packet->chunk_length); + + assert(packet->total_length > 0 + && packet->total_length < MAX_ATTRIBUTE_BLOCK); + /* 500 bytes header, just to be sure */ + assert(packet->chunk_length > 0 + && packet->chunk_length < MAX_LEN_PACKET - 500); + assert(packet->chunk_length <= packet->total_length); + assert(packet->offset >= 0 && packet->offset < packet->total_length); + + assert(pack_iter_remaining(&iter) != -1); + assert(pack_iter_remaining(&iter) == packet->chunk_length); + + memcpy(packet->data, iter.ptr, packet->chunk_length); + + pack_iter_end(&iter, pc); + remove_packet_from_buffer(pc->buffer); + + return packet; +} + +/************************************************************************** + Updates pplayer->attribute_block according to the given packet. +**************************************************************************/ +void generic_handle_attribute_chunk(struct player *pplayer, + struct packet_attribute_chunk *chunk) +{ + /* first one in a row */ + if (chunk->offset == 0) { + if (pplayer->attribute_block.data != NULL) { + free(pplayer->attribute_block.data); + pplayer->attribute_block.data = NULL; + } + pplayer->attribute_block.data = fc_malloc(chunk->total_length); + pplayer->attribute_block.length = chunk->total_length; + } + memcpy(pplayer->attribute_block.data + chunk->offset, + chunk->data, chunk->chunk_length); +} +/************************************************************************** + Split the attribute block into chunks and send them over pconn. +**************************************************************************/ +void send_attribute_block(const struct player *pplayer, + struct connection *pconn) +{ + struct packet_attribute_chunk packet; + int current_chunk, chunks, bytes_left; + + if (pplayer->attribute_block.data == NULL) + return; + + assert(pplayer->attribute_block.length > 0 && + pplayer->attribute_block.length < MAX_ATTRIBUTE_BLOCK); + + chunks = + (pplayer->attribute_block.length - 1) / ATTRIBUTE_CHUNK_SIZE + 1; + bytes_left = pplayer->attribute_block.length; + + connection_do_buffer(pconn); + + for (current_chunk = 0; current_chunk < chunks; current_chunk++) { + int size_of_current_chunk = MIN(bytes_left, ATTRIBUTE_CHUNK_SIZE); + + packet.offset = ATTRIBUTE_CHUNK_SIZE * current_chunk; + packet.total_length = pplayer->attribute_block.length; + packet.chunk_length = size_of_current_chunk; + + memcpy(packet.data, pplayer->attribute_block.data + packet.offset, + packet.chunk_length); + bytes_left -= packet.chunk_length; + + send_packet_attribute_chunk(pconn, &packet); + } + + connection_do_unbuffer(pconn); } diff -ruN -X freeciv/diff_ignore freeciv/common/packets.h freeciv.mod/common/packets.h --- freeciv/common/packets.h Sat Oct 28 00:20:09 2000 +++ freeciv.mod/common/packets.h Mon Jan 15 15:17:26 2001 @@ -20,8 +20,10 @@ #include "spaceship.h" #include "worklist.h" -#define MAX_LEN_USERNAME 10 /* see below */ -#define MAX_LEN_MSG 1536 +#define MAX_LEN_USERNAME 10 /* see below */ +#define MAX_LEN_MSG 1536 +#define MAX_ATTRIBUTE_BLOCK (1024*64) /* largest attribute block */ +#define ATTRIBUTE_CHUNK_SIZE (1024*2) /* attribute chunk size to use */ /* Note that MAX_LEN_USERNAME cannot be expanded, because it is used for the name in the first packet sent by the client, @@ -115,6 +117,8 @@ PACKET_PLAYER_REMOVE_VISION, PACKET_GOTO_ROUTE, PACKET_PATROL_ROUTE, + PACKET_ATTRIBUTE_CHUNK, + PACKET_PLAYER_ATTRIBUTE_BLOCK, PACKET_LAST /* leave this last */ }; @@ -231,6 +235,7 @@ int tech; /* research */ struct worklist worklist; /* one worklist */ int wl_idx; /* which worklist */ + int attribute_block; /* send attribute block as chunks */ }; /********************************************************* @@ -848,6 +853,13 @@ int unit_id; }; +struct packet_attribute_chunk +{ + int offset, total_length, chunk_length; + /* to keep memory management simple don't allocate dynamic memory */ + unsigned char data[ATTRIBUTE_CHUNK_SIZE]; +}; + /* These two are non-static for meta.c; others are now static --dwp */ unsigned char *put_uint16(unsigned char *buffer, int val); unsigned char *put_string(unsigned char *buffer, char *mystring); @@ -1056,6 +1068,16 @@ int send_packet_goto_route(struct connection *pc, struct packet_goto_route *packet, enum goto_route_type type); struct packet_goto_route *receive_packet_goto_route(struct connection *pc); + +int send_packet_attribute_chunk(struct connection *pc, + struct packet_attribute_chunk *packet); +struct packet_attribute_chunk *receive_packet_attribute_chunk(struct + connection + *pc); +void send_attribute_block(const struct player *pplayer, + struct connection *pconn); +void generic_handle_attribute_chunk(struct player *pplayer, + struct packet_attribute_chunk *chunk); #include "packets_lsend.h" /* lsend_packet_* functions */ diff -ruN -X freeciv/diff_ignore freeciv/common/player.c freeciv.mod/common/player.c --- freeciv/common/player.c Sat Oct 21 07:18:35 2000 +++ freeciv.mod/common/player.c Mon Jan 15 11:15:23 2001 @@ -101,6 +101,8 @@ } plr->gives_shared_vision = 0; plr->really_gives_vision = 0; + plr->attribute_block.data = NULL; + plr->attribute_block.length = 0; } /*************************************************************** diff -ruN -X freeciv/diff_ignore freeciv/common/player.h freeciv.mod/common/player.h --- freeciv/common/player.h Wed Sep 6 23:41:16 2000 +++ freeciv.mod/common/player.h Mon Jan 15 11:13:53 2001 @@ -45,7 +45,6 @@ /* anything else I have forgotten? Let me know. -- Syela */ }; - struct player_economic { int gold; int tax; @@ -158,6 +157,10 @@ struct player_tile *private_map; unsigned int gives_shared_vision; /* bitvector those that give you shared vision */ unsigned int really_gives_vision; /* takes into account that p3 may see what p1 has via p2 */ + struct { + int length; + void *data; + } attribute_block; }; void player_init(struct player *plr); diff -ruN -X freeciv/diff_ignore freeciv/server/plrhand.c freeciv.mod/server/plrhand.c --- freeciv/server/plrhand.c Wed Jan 10 17:52:57 2001 +++ freeciv.mod/server/plrhand.c Mon Jan 15 12:57:19 2001 @@ -1430,3 +1430,21 @@ return &game.players[i]; } } + +/************************************************************************** + The client has send as a chunk of the attribute block. +**************************************************************************/ +void handle_player_attribute_chunk(struct player *pplayer, + struct packet_attribute_chunk *chunk) +{ + generic_handle_attribute_chunk(pplayer, chunk); +} + +/************************************************************************** + The client request an attribute block. +**************************************************************************/ +void handle_player_attribute_block(struct player *pplayer, + struct packet_player_request *packet) +{ + send_attribute_block(pplayer, pplayer->current_conn); +} diff -ruN -X freeciv/diff_ignore freeciv/server/plrhand.h freeciv.mod/server/plrhand.h --- freeciv/server/plrhand.h Tue Jan 9 00:44:35 2001 +++ freeciv.mod/server/plrhand.h Mon Jan 15 12:57:40 2001 @@ -14,6 +14,7 @@ #define FC__PLRHAND_H #include "attribute.h" +#include "packets.h" struct player; struct packet_player_request; @@ -66,6 +67,10 @@ struct packet_player_request *preq); void handle_player_worklist(struct player *pplayer, struct packet_player_request *preq); +void handle_player_attribute_chunk(struct player *pplayer, + struct packet_attribute_chunk *preq); +void handle_player_attribute_block(struct player *pplayer, + struct packet_player_request *packet); void found_new_tech(struct player *plr, int tech_found, char was_discovery, char saving_bulbs); void tech_researched(struct player* plr); diff -ruN -X freeciv/diff_ignore freeciv/server/savegame.c freeciv.mod/server/savegame.c --- freeciv/server/savegame.c Thu Jan 4 01:49:06 2001 +++ freeciv.mod/server/savegame.c Mon Jan 15 16:12:12 2001 @@ -59,8 +59,53 @@ * include it when appropriate for maximum savegame compatibility.) */ #define SAVEFILE_OPTIONS "1.7 startoptions spacerace2 rulesets" \ -" diplchance_percent worklists2 map_editor" +" diplchance_percent worklists2 map_editor attributes" +/*************************************************************** +Quote the memory block denoted by data and length so it consists only +of " a-f0-9:". The returned string has the freed by the caller using +free(). +***************************************************************/ +char *quote_block(void *data, int length) +{ + char *buffer = malloc(length * 3 + 10); + int offset, i; + + sprintf(buffer, "%d:", length); + offset = strlen(buffer); + + for (i = 0; i < length; i++) { + sprintf(buffer + offset, "%02x ", ((unsigned char *) data)[i]); + offset += 3; + } + return buffer; +} + +/*************************************************************** +Unquote a string. The unquoted data is written into dest. If the +unqoted data will be largern than dest_length the function aborts. It +returns the actual length of the unquoted block. +***************************************************************/ +int unquote_block(char *quoted, void *dest, int dest_length) +{ + int i, length, parsed; + + parsed = sscanf(quoted, "%d", &length); + assert(parsed == 1); + + assert(length <= dest_length); + quoted = strchr(quoted, ':') + 1; + + for (i = 0; i < length; i++) { + int tmp; + parsed = sscanf(quoted, "%x", &tmp); + assert(parsed == 1); + assert((tmp & 0xff) == tmp); + ((unsigned char *) dest)[i] = tmp; + quoted += 3; + } + return length; +} /*************************************************************** load starting positions for the players from a savegame file @@ -985,6 +1030,44 @@ unit_list_insert(&map_get_tile(punit->x, punit->y)->units, punit); } + + if (section_file_lookup(file, "player%d.attribute_block_length", plrno)) { + int raw_length1, raw_length2, part_nr, parts; + char *quoted; + + raw_length1 = + secfile_lookup_int(file, "player%d.attribute_block_length", plrno); + if (plr->attribute_block.data != NULL) { + free(plr->attribute_block.data); + plr->attribute_block.data = NULL; + } + plr->attribute_block.data = fc_malloc(raw_length1); + plr->attribute_block.length = raw_length1; + + quoted = + fc_malloc(secfile_lookup_int + (file, "player%d.attribute_block_length_quoted", + plrno) + 1); + quoted[0] = 0; + + parts = + secfile_lookup_int(file, "player%d.attribute_block_parts", plrno); + + for (part_nr = 0; part_nr < parts; part_nr++) { + char *current = secfile_lookup_str(file, + "player%d.attribute_block_data.part%d", + plrno, part_nr); + if (!current) + break; + strcat(quoted, current); + } + raw_length2 = + unquote_block(quoted, + plr->attribute_block.data, + plr->attribute_block.length); + assert(raw_length1 == raw_length2); + free(quoted); + } } /********************************************************************** @@ -1552,6 +1635,37 @@ } } secfile_insert_int(file, i, "player%d.total_ncities", plrno); + +#define PART_SIZE (2*1024) + if (plr->attribute_block.data != NULL) { + char *quoted = quote_block(plr->attribute_block.data, + plr->attribute_block.length); + char part[PART_SIZE+1]; + int current_part_nr,parts,bytes_left; + + secfile_insert_int(file, plr->attribute_block.length, + "player%d.attribute_block_length", plrno); + secfile_insert_int(file, strlen(quoted), + "player%d.attribute_block_length_quoted", plrno); + + parts = (strlen(quoted) - 1) / PART_SIZE + 1; + bytes_left = strlen(quoted); + + secfile_insert_int(file, parts, + "player%d.attribute_block_parts", plrno); + + for (current_part_nr = 0; current_part_nr < parts; current_part_nr++) { + int size_of_current_part = MIN(bytes_left, PART_SIZE); + + memcpy(part, quoted + PART_SIZE * current_part_nr, + size_of_current_part); + part[PART_SIZE] = 0; + secfile_insert_str(file, part, "player%d.attribute_block_data.part%d", + plrno, current_part_nr); + + } + free(quoted); + } } } diff -ruN -X freeciv/diff_ignore freeciv/server/srv_main.c freeciv.mod/server/srv_main.c --- freeciv/server/srv_main.c Tue Jan 9 00:44:35 2001 +++ freeciv.mod/server/srv_main.c Mon Jan 15 14:45:12 2001 @@ -1115,6 +1115,17 @@ case PACKET_PATROL_ROUTE: handle_patrol_route(pplayer, (struct packet_goto_route *)packet); break; + case PACKET_ATTRIBUTE_CHUNK: + handle_player_attribute_chunk(pplayer, + (struct packet_attribute_chunk *) + packet); + break; + case PACKET_PLAYER_ATTRIBUTE_BLOCK: + handle_player_attribute_block(pplayer, + (struct packet_player_request *) + packet); + break; + default: freelog(LOG_ERROR, "Received unknown packet %d from %s", type, conn_description(pconn));