Freeciv-3.1: /fast/freeciv/nightly/S3_1/client/attribute.c Source File

Freeciv-3.1

Loading...
Searching...
No Matches
attribute.c
Go to the documentation of this file.
1/***********************************************************************
2 Freeciv - Copyright (C) 2001 - R. Falke
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12***********************************************************************/
13
14#ifdef HAVE_CONFIG_H
15#include <fc_config.h>
16#endif
17
18/* utility */
19#include "dataio.h"
20#include "fcintl.h"
21#include "genhash.h" /* genhash_val_t */
22#include "log.h"
23#include "mem.h"
24
25/* common */
26#include "packets.h"
27
28/* client */
29#include "client_main.h"
30
31#include "attribute.h"
32
33#define log_attribute log_debug
34
35 enum attribute_serial {
36 A_SERIAL_FAIL,
37 A_SERIAL_OK,
38 A_SERIAL_OLD,
39};
40
41 struct attr_key {
42 int key, id, x, y;
43};
44
45static genhash_val_t attr_key_val(const struct attr_key *pkey);
46static bool attr_key_comp(const struct attr_key *pkey1,
47 const struct attr_key *pkey2);
48static struct attr_key *attr_key_dup(const struct attr_key *pkey);
49static void attr_key_destroy(struct attr_key *pkey);
50
51/* 'struct attribute_hash' and related functions. */
52#define SPECHASH_TAG attribute
53#define SPECHASH_IKEY_TYPE struct attr_key *
54#define SPECHASH_IDATA_TYPE void *
55#define SPECHASH_IKEY_VAL attr_key_val
56#define SPECHASH_IKEY_COMP attr_key_comp
57#define SPECHASH_IKEY_COPY attr_key_dup
58#define SPECHASH_IKEY_FREE attr_key_destroy
59#define SPECHASH_IDATA_FREE free
60#include "spechash.h"
61#define attribute_hash_values_iterate(hash, pvalue) \
62 TYPED_HASH_DATA_ITERATE(void *, hash, pvalue)
63#define attribute_hash_values_iterate_end HASH_DATA_ITERATE_END
64#define attribute_hash_iterate(hash, pkey, pvalue) \
65 TYPED_HASH_ITERATE(const struct attr_key *, void *, hash, pkey, pvalue)
66#define attribute_hash_iterate_end HASH_ITERATE_END
67
68
69 static struct attribute_hash *attribute_hash = NULL;
70
71/************************************************************************/
74 static genhash_val_t attr_key_val(const struct attr_key *pkey)
75{
76 return (genhash_val_t) pkey->id ^ pkey->x ^ pkey->y ^ pkey->key;
77}
78
79/************************************************************************/
82 static bool attr_key_comp(const struct attr_key *pkey1,
83 const struct attr_key *pkey2)
84{
85 return pkey1->key == pkey2->key
86 && pkey1->id == pkey2->id
87 && pkey1->x == pkey2->x
88 && pkey1->y == pkey2->y;
89}
90
91/************************************************************************/
94 static struct attr_key *attr_key_dup(const struct attr_key *pkey)
95{
96 struct attr_key *pnew_key = fc_malloc(sizeof(*pnew_key));
97
98 *pnew_key = *pkey;
99 return pnew_key;
100}
101
102/************************************************************************/
105 static void attr_key_destroy(struct attr_key *pkey)
106{
107 fc_assert_ret(NULL != pkey);
108 free(pkey);
109}
110
111/************************************************************************/
114 void attribute_init(void)
115{
116 fc_assert(NULL == attribute_hash);
117 attribute_hash = attribute_hash_new();
118}
119
120/************************************************************************/
123 void attribute_free(void)
124{
125 fc_assert_ret(NULL != attribute_hash);
126 attribute_hash_destroy(attribute_hash);
127 attribute_hash = NULL;
128}
129
130/************************************************************************/
133static enum attribute_serial
134serialize_hash(const struct attribute_hash *hash,
135 void **pdata, int *pdata_length)
136{
137 /*
138 * Layout of version 2:
139 *
140 * struct {
141 * uint32 0; always != 0 in version 1
142 * uint8 2;
143 * uint32 entries;
144 * uint32 total_size_in_bytes;
145 * } preamble;
146 *
147 * struct {
148 * uint32 value_size;
149 * char key[], char value[];
150 * } body[entries];
151 */
152 const size_t entries = attribute_hash_size(hash);
153 int total_length, value_lengths[entries];
154 void *result;
155 struct raw_data_out dout;
156 int i;
157
158 /*
159 * Step 1: loop through all keys and fill value_lengths and calculate
160 * the total_length.
161 */
162 /* preamble */
163 total_length = 4 + 1 + 4 + 4;
164 /* body */
165 total_length += entries * (4 + 4 + 4 + 2 + 2); /* value_size + key */
166 i = 0;
167 attribute_hash_values_iterate(hash, pvalue) {
168 struct data_in din;
169
170 dio_input_init(&din, pvalue, 4);
171 dio_get_uint32_raw(&din, &value_lengths[i]);
172
173 total_length += value_lengths[i];
174 i++;
175 } attribute_hash_values_iterate_end;
176
177 /*
178 * Step 2: allocate memory.
179 */
180 result = fc_malloc(total_length);
181 dio_output_init(&dout, result, total_length);
182
183 /*
184 * Step 3: fill out the preamble.
185 */
186 dio_put_uint32_raw(&dout, 0);
187 dio_put_uint8_raw(&dout, 2);
188 dio_put_uint32_raw(&dout, attribute_hash_size(hash));
189 dio_put_uint32_raw(&dout, total_length);
190
191 /*
192 * Step 4: fill out the body.
193 */
194 i = 0;
195 attribute_hash_iterate(hash, pkey, pvalue) {
196 dio_put_uint32_raw(&dout, value_lengths[i]);
197
198 dio_put_uint32_raw(&dout, pkey->key);
199 dio_put_uint32_raw(&dout, pkey->id);
200 dio_put_sint16_raw(&dout, pkey->x);
201 dio_put_sint16_raw(&dout, pkey->y);
202
203 dio_put_memory_raw(&dout, ADD_TO_POINTER(pvalue, 4), value_lengths[i]);
204 i++;
205 } attribute_hash_iterate_end;
206
207 fc_assert(!dout.too_short);
208 fc_assert_msg(dio_output_used(&dout) == total_length,
209 "serialize_hash() total_length = %lu, actual = %lu",
210 (long unsigned)total_length,
211 (long unsigned)dio_output_used(&dout));
212
213 /*
214 * Step 5: return.
215 */
216 *pdata = result;
217 *pdata_length = total_length;
218 log_attribute("attribute.c serialize_hash() "
219 "serialized %lu entries in %lu bytes",
220 (long unsigned) entries, (long unsigned) total_length);
221 return A_SERIAL_OK;
222}
223
224/************************************************************************/
230 static enum attribute_serial unserialize_hash(struct attribute_hash *hash,
231 const void *data,
232 size_t data_length)
233{
234 int entries, i, dummy;
235 struct data_in din;
236
237 attribute_hash_clear(hash);
238
239 dio_input_init(&din, data, data_length);
240
241 dio_get_uint32_raw(&din, &dummy);
242 if (dummy != 0) {
243 log_verbose("attribute.c unserialize_hash() preamble, uint32 %lu != 0",
244 (long unsigned) dummy);
245 return A_SERIAL_OLD;
246 }
247 dio_get_uint8_raw(&din, &dummy);
248 if (dummy != 2) {
249 log_verbose("attribute.c unserialize_hash() preamble, "
250 "uint8 %lu != 2 version", (long unsigned) dummy);
251 return A_SERIAL_OLD;
252 }
253 dio_get_uint32_raw(&din, &entries);
254 dio_get_uint32_raw(&din, &dummy);
255 if (dummy != data_length) {
256 log_verbose("attribute.c unserialize_hash() preamble, "
257 "uint32 %lu != %lu data_length",
258 (long unsigned) dummy, (long unsigned) data_length);
259 return A_SERIAL_FAIL;
260 }
261
262 log_attribute("attribute.c unserialize_hash() "
263 "uint32 %lu entries, %lu data_length",
264 (long unsigned) entries, (long unsigned) data_length);
265
266 for (i = 0; i < entries; i++) {
267 struct attr_key key;
268 void *pvalue;
269 int value_length;
270 struct raw_data_out dout;
271
272 if (!dio_get_uint32_raw(&din, &value_length)) {
273 log_verbose("attribute.c unserialize_hash() "
274 "uint32 value_length dio_input_too_short");
275 return A_SERIAL_FAIL;
276 }
277 log_attribute("attribute.c unserialize_hash() "
278 "uint32 %lu value_length", (long unsigned) value_length);
279
280 /* next 12 bytes */
281 if (!dio_get_uint32_raw(&din, &key.key)
282 || !dio_get_uint32_raw(&din, &key.id)
283 || !dio_get_sint16_raw(&din, &key.x)
284 || !dio_get_sint16_raw(&din, &key.y)) {
285 log_verbose("attribute.c unserialize_hash() "
286 "uint32 key dio_input_too_short");
287 return A_SERIAL_FAIL;
288 }
289 pvalue = fc_malloc(value_length + 4);
290
291 dio_output_init(&dout, pvalue, value_length + 4);
292 dio_put_uint32_raw(&dout, value_length);
293 if (!dio_get_memory_raw(&din, ADD_TO_POINTER(pvalue, 4), value_length)) {
294 log_verbose("attribute.c unserialize_hash() "
295 "memory dio_input_too_short");
296 return A_SERIAL_FAIL;
297 }
298
299 if (!attribute_hash_insert(hash, &key, pvalue)) {
300 /* There are some untraceable attribute bugs caused by the CMA that
301 * can cause this to happen. I think the only safe thing to do is
302 * to delete all attributes. Another symptom of the bug is the
303 * value_length (above) is set to a random value, which can also
304 * cause a bug. */
305 free(pvalue);
306 attribute_hash_clear(hash);
307 return A_SERIAL_FAIL;
308 }
309 }
310
311 if (dio_input_remaining(&din) > 0) {
312 /* This is not an error, as old clients sent overlong serialized
313 * attributes pre gna bug #21295, and these will be hanging around
314 * in savefiles forever. */
315 log_attribute("attribute.c unserialize_hash() "
316 "ignored %lu trailing octets",
317 (long unsigned) dio_input_remaining(&din));
318 }
319
320 return A_SERIAL_OK;
321}
322
323/************************************************************************/
327 void attribute_flush(void)
328{
329 struct player *pplayer = client_player();
330
331 if (!pplayer || client_is_observer() || !pplayer->is_alive) {
332 return;
333 }
334
335 fc_assert_ret(NULL != attribute_hash);
336
337 if (0 == attribute_hash_size(attribute_hash))
338 return;
339
340 if (pplayer->attribute_block.data) {
341 free(pplayer->attribute_block.data);
342 pplayer->attribute_block.data = NULL;
343 }
344
345 serialize_hash(attribute_hash, &pplayer->attribute_block.data,
346 &pplayer->attribute_block.length);
347 send_attribute_block(pplayer, &client.conn);
348}
349
350/************************************************************************/
354 void attribute_restore(void)
355{
356 struct player *pplayer = client_player();
357
358 if (!pplayer) {
359 return;
360 }
361
362 fc_assert_ret(attribute_hash != NULL);
363
364 switch (unserialize_hash(attribute_hash,
365 pplayer->attribute_block.data,
366 pplayer->attribute_block.length)) {
367 case A_SERIAL_FAIL:
368 log_error(_("There has been a CMA error. "
369 "Your citizen governor settings may be broken."));
370 break;
371 case A_SERIAL_OLD:
372 log_normal(_("Old attributes detected and removed."));
373 break;
374 default:
375 break;
376 };
377}
378
379/************************************************************************/
383 void attribute_set(int key, int id, int x, int y, size_t data_length,
384 const void *const data)
385{
386 struct attr_key akey = { .key = key, .id = id, .x = x, .y = y };
387
388 log_attribute("attribute_set(key = %d, id = %d, x = %d, y = %d, "
389 "data_length = %lu, data = %p)", key, id, x, y,
390 (long unsigned) data_length, data);
391
392 fc_assert_ret(NULL != attribute_hash);
393
394 if (0 != data_length) {
395 void *pvalue = fc_malloc(data_length + 4);
396 struct raw_data_out dout;
397
398 dio_output_init(&dout, pvalue, data_length + 4);
399 dio_put_uint32_raw(&dout, data_length);
400 dio_put_memory_raw(&dout, data, data_length);
401
402 attribute_hash_replace(attribute_hash, &akey, pvalue);
403 } else {
404 attribute_hash_remove(attribute_hash, &akey);
405 }
406}
407
408/************************************************************************/
415 size_t attribute_get(int key, int id, int x, int y, size_t max_data_length,
416 void *data)
417{
418 struct attr_key akey = { .key = key, .id = id, .x = x, .y = y };
419 void *pvalue;
420 int length;
421 struct data_in din;
422
423 log_attribute("attribute_get(key = %d, id = %d, x = %d, y = %d, "
424 "max_data_length = %lu, data = %p)", key, id, x, y,
425 (long unsigned) max_data_length, data);
426
427 fc_assert_ret_val(NULL != attribute_hash, 0);
428
429 if (!attribute_hash_lookup(attribute_hash, &akey, &pvalue)) {
430 log_attribute(" not found");
431 return 0;
432 }
433
434 dio_input_init(&din, pvalue, 0xffffffff);
435 dio_get_uint32_raw(&din, &length);
436
437 if (length <= max_data_length) {
438 dio_get_memory_raw(&din, data, length);
439 }
440
441 log_attribute(" found length = %d", length);
442 return length;
443}
444
445/************************************************************************/
448 void attr_unit_set(enum attr_unit what, int unit_id, size_t data_length,
449 const void *const data)
450{
451 attribute_set(what, unit_id, -1, -2, data_length, data);
452}
453
454/************************************************************************/
457 size_t attr_unit_get(enum attr_unit what, int unit_id, size_t max_data_length,
458 void *data)
459{
460 return attribute_get(what, unit_id, -1, -2, max_data_length, data);
461}
462
463/************************************************************************/
466 void attr_unit_set_int(enum attr_unit what, int unit_id, int data)
467{
468 attr_unit_set(what, unit_id, sizeof(int), &data);
469}
470
471/************************************************************************/
474 size_t attr_unit_get_int(enum attr_unit what, int unit_id, int *data)
475{
476 return attr_unit_get(what, unit_id, sizeof(int), data);
477}
478
479/************************************************************************/
482 void attr_city_set(enum attr_city what, int city_id, size_t data_length,
483 const void *const data)
484{
485 attribute_set(what, city_id, -1, -1, data_length, data);
486}
487
488/************************************************************************/
491 size_t attr_city_get(enum attr_city what, int city_id, size_t max_data_length,
492 void *data)
493{
494 return attribute_get(what, city_id, -1, -1, max_data_length, data);
495}
496
497/************************************************************************/
500 void attr_city_set_int(enum attr_city what, int city_id, int data)
501{
502 attr_city_set(what, city_id, sizeof(int), &data);
503}
504
505/************************************************************************/
508 size_t attr_city_get_int(enum attr_city what, int city_id, int *data)
509{
510 return attr_city_get(what, city_id, sizeof(int), data);
511}
512
513/************************************************************************/
516 void attr_player_set(enum attr_player what, int player_id, size_t data_length,
517 const void *const data)
518{
519 attribute_set(what, player_id, -1, -1, data_length, data);
520}
521
522/************************************************************************/
525 size_t attr_player_get(enum attr_player what, int player_id,
526 size_t max_data_length, void *data)
527{
528 return attribute_get(what, player_id, -1, -1, max_data_length, data);
529}
530
531/************************************************************************/
534 void attr_tile_set(enum attr_tile what, int x, int y, size_t data_length,
535 const void *const data)
536{
537 attribute_set(what, -1, x, y, data_length, data);
538}
539
540/************************************************************************/
543 size_t attr_tile_get(enum attr_tile what, int x, int y, size_t max_data_length,
544 void *data)
545{
546 return attribute_get(what, -1, x, y, max_data_length, data);
547}
entries
struct @124::my_agent entries[MAX_AGENTS]
attribute_set
void attribute_set(int key, int id, int x, int y, size_t data_length, const void *const data)
Definition attribute.c:383
attribute_hash
static struct attribute_hash * attribute_hash
Definition attribute.c:69
attr_city_get_int
size_t attr_city_get_int(enum attr_city what, int city_id, int *data)
Definition attribute.c:508
attr_key_destroy
static void attr_key_destroy(struct attr_key *pkey)
Definition attribute.c:105
attribute_init
void attribute_init(void)
Definition attribute.c:114
attribute_free
void attribute_free(void)
Definition attribute.c:123
attr_tile_get
size_t attr_tile_get(enum attr_tile what, int x, int y, size_t max_data_length, void *data)
Definition attribute.c:543
attr_player_set
void attr_player_set(enum attr_player what, int player_id, size_t data_length, const void *const data)
Definition attribute.c:516
attr_unit_get_int
size_t attr_unit_get_int(enum attr_unit what, int unit_id, int *data)
Definition attribute.c:474
attr_tile_set
void attr_tile_set(enum attr_tile what, int x, int y, size_t data_length, const void *const data)
Definition attribute.c:534
unserialize_hash
static enum attribute_serial unserialize_hash(struct attribute_hash *hash, const void *data, size_t data_length)
Definition attribute.c:230
attribute_flush
void attribute_flush(void)
Definition attribute.c:327
attribute_hash_iterate_end
#define attribute_hash_iterate_end
Definition attribute.c:66
attribute_get
size_t attribute_get(int key, int id, int x, int y, size_t max_data_length, void *data)
Definition attribute.c:415
attr_city_get
size_t attr_city_get(enum attr_city what, int city_id, size_t max_data_length, void *data)
Definition attribute.c:491
attr_key_dup
static struct attr_key * attr_key_dup(const struct attr_key *pkey)
Definition attribute.c:94
attribute_hash_values_iterate_end
#define attribute_hash_values_iterate_end
Definition attribute.c:63
attr_key_val
static genhash_val_t attr_key_val(const struct attr_key *pkey)
Definition attribute.c:74
attribute_restore
void attribute_restore(void)
Definition attribute.c:354
attr_unit_set
void attr_unit_set(enum attr_unit what, int unit_id, size_t data_length, const void *const data)
Definition attribute.c:448
attr_unit_get
size_t attr_unit_get(enum attr_unit what, int unit_id, size_t max_data_length, void *data)
Definition attribute.c:457
attr_player_get
size_t attr_player_get(enum attr_player what, int player_id, size_t max_data_length, void *data)
Definition attribute.c:525
serialize_hash
static enum attribute_serial serialize_hash(const struct attribute_hash *hash, void **pdata, int *pdata_length)
Definition attribute.c:134
attribute_serial
attribute_serial
Definition attribute.c:35
A_SERIAL_OLD
@ A_SERIAL_OLD
Definition attribute.c:38
A_SERIAL_OK
@ A_SERIAL_OK
Definition attribute.c:37
A_SERIAL_FAIL
@ A_SERIAL_FAIL
Definition attribute.c:36
attribute_hash_iterate
#define attribute_hash_iterate(hash, pkey, pvalue)
Definition attribute.c:64
attr_unit_set_int
void attr_unit_set_int(enum attr_unit what, int unit_id, int data)
Definition attribute.c:466
attr_key_comp
static bool attr_key_comp(const struct attr_key *pkey1, const struct attr_key *pkey2)
Definition attribute.c:82
attr_city_set_int
void attr_city_set_int(enum attr_city what, int city_id, int data)
Definition attribute.c:500
attr_city_set
void attr_city_set(enum attr_city what, int city_id, size_t data_length, const void *const data)
Definition attribute.c:482
attribute_hash_values_iterate
#define attribute_hash_values_iterate(hash, pvalue)
Definition attribute.c:61
log_attribute
#define log_attribute
Definition attribute.c:33
attribute.h
attr_city
attr_city
Definition attribute.h:37
attr_unit
attr_unit
Definition attribute.h:33
attr_tile
attr_tile
Definition attribute.h:46
attr_player
attr_player
Definition attribute.h:42
client_is_observer
bool client_is_observer(void)
Definition client_main.c:1086
client
struct civclient client
Definition client_main.c:149
client_main.h
client_player
#define client_player()
Definition client_main.h:106
dataio.h
dio_output_init
void dio_output_init(struct raw_data_out *dout, void *destination, size_t dest_size)
Definition dataio_raw.c:171
dio_input_remaining
size_t dio_input_remaining(struct data_in *din)
Definition dataio_raw.c:221
dio_put_uint8_raw
void dio_put_uint8_raw(struct raw_data_out *dout, int value)
Definition dataio_raw.c:265
dio_put_sint16_raw
void dio_put_sint16_raw(struct raw_data_out *dout, int value)
Definition dataio_raw.c:361
dio_get_uint32_raw
bool dio_get_uint32_raw(struct data_in *din, int *dest)
Definition dataio_raw.c:614
dio_get_sint16_raw
bool dio_get_sint16_raw(struct data_in *din, int *dest)
Definition dataio_raw.c:751
dio_put_uint32_raw
void dio_put_uint32_raw(struct raw_data_out *dout, int value)
Definition dataio_raw.c:303
dio_get_memory_raw
bool dio_get_memory_raw(struct data_in *din, void *dest, size_t dest_size)
Definition dataio_raw.c:790
dio_put_memory_raw
void dio_put_memory_raw(struct raw_data_out *dout, const void *value, size_t size)
Definition dataio_raw.c:488
dio_get_uint8_raw
bool dio_get_uint8_raw(struct data_in *din, int *dest)
Definition dataio_raw.c:572
dio_output_used
size_t dio_output_used(struct raw_data_out *dout)
Definition dataio_raw.c:184
dio_input_init
void dio_input_init(struct data_in *din, const void *src, size_t src_size)
Definition dataio_raw.c:202
id
int int id
Definition editgui_g.h:28
fcintl.h
_
#define _(String)
Definition fcintl.h:67
genhash.h
genhash_val_t
unsigned int genhash_val_t
Definition genhash.h:32
hash
static GHashTable * hash
Definition wldlg.c:320
log.h
fc_assert_msg
#define fc_assert_msg(condition, message,...)
Definition log.h:181
fc_assert_ret
#define fc_assert_ret(condition)
Definition log.h:191
log_verbose
#define log_verbose(message,...)
Definition log.h:109
fc_assert
#define fc_assert(condition)
Definition log.h:176
fc_assert_ret_val
#define fc_assert_ret_val(condition, val)
Definition log.h:194
log_normal
#define log_normal(message,...)
Definition log.h:107
log_error
#define log_error(message,...)
Definition log.h:103
mem.h
fc_malloc
#define fc_malloc(sz)
Definition mem.h:34
send_attribute_block
void send_attribute_block(const struct player *pplayer, struct connection *pconn)
Definition packets.c:746
packets.h
ADD_TO_POINTER
#define ADD_TO_POINTER(p, n)
Definition shared.h:86
spechash.h
attr_key
Definition attribute.c:41
attr_key::y
int y
Definition attribute.c:42
attr_key::key
int key
Definition attribute.c:42
attr_key::x
int x
Definition attribute.c:42
attr_key::id
int id
Definition attribute.c:42
attribute_block_s::data
void * data
Definition player.h:223
attribute_block_s::length
int length
Definition player.h:224
civclient::conn
struct connection conn
Definition client_main.h:96
data_in
Definition dataio_raw.h:30
player
Definition player.h:249
player::is_alive
bool is_alive
Definition player.h:268
player::attribute_block
struct attribute_block_s attribute_block
Definition player.h:303
raw_data_out
Definition dataio_raw.h:35
raw_data_out::too_short
bool too_short
Definition dataio_raw.h:38