Freeciv-3.3
Loading...
Searching...
No Matches
cma_core.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#include <string.h>
19#ifdef HAVE_UNISTD_H
20#include <unistd.h>
21#endif
22
23/* utility */
24#include "bugs.h"
25#include "fcintl.h"
26#include "log.h"
27#include "mem.h"
28#include "shared.h" /* for MIN() */
29#include "specialist.h"
30#include "support.h"
31#include "timing.h"
32
33/* common */
34#include "city.h"
35#include "dataio.h"
36#include "events.h"
37#include "game.h"
38#include "government.h"
39#include "nation.h"
40#include "packets.h"
41#include "specialist.h"
42
43/* client */
44#include "attribute.h"
45#include "client_main.h"
46#include "climisc.h"
47#include "packhand.h"
48
49/* client/include */
50#include "chatline_g.h"
51#include "citydlg_g.h"
52#include "cityrep_g.h"
53#include "messagewin_g.h"
54
55/* client/agents */
56#include "agents.h"
57
58#include "cma_core.h"
59
60
61/*
62 * The CMA is an agent. The CMA will subscribe itself to all city
63 * events. So if a city changes the callback function city_changed is
64 * called. handle_city will be called from city_changed to update the
65 * given city. handle_city will call cma_query_result and
66 * apply_result_on_server to update the server city state.
67 */
68
69/****************************************************************************
70 Defines, structs, globals, forward declarations
71*****************************************************************************/
72
73#define log_apply_result log_debug
74#define log_handle_city log_debug
75#define log_handle_city2 log_debug
76#define log_results_are_equal log_debug
77
78#define SHOW_TIME_STATS FALSE
79#define SHOW_APPLY_RESULT_ON_SERVER_ERRORS FALSE
80#define ALWAYS_APPLY_AT_SERVER FALSE
81
82#define SAVED_PARAMETER_SIZE 30
83#define SAVED_PARAMETER_SIZE_OLD 29
84
85#define CMA_ATTR_VERSION 3
86#define CMA_ATTR_VERSION_MIN_SUPPORTED 2
87
88/*
89 * Misc statistic to analyze performance.
90 */
91static struct {
95
96/************************************************************************/
100static bool fc_results_are_equal(const struct cm_result *result1,
101 const struct cm_result *result2)
102{
103#define T(x) if (result1->x != result2->x) { \
104 log_results_are_equal(#x); \
105 return FALSE; }
106
107 T(disorder);
108 T(happy);
109
111 T(specialists[sp]);
113
115 T(surplus[ot]);
117
118 fc_assert_ret_val(result1->city_radius_sq == result2->city_radius_sq,
119 FALSE);
120 city_map_iterate(result1->city_radius_sq, cindex, x, y) {
121 if (is_free_worked_index(cindex)) {
122 continue;
123 }
124
125 if (result1->worker_positions[cindex]
126 != result2->worker_positions[cindex]) {
127 log_results_are_equal("worker_positions");
128
129 return FALSE;
130 }
132
133 return TRUE;
134
135#undef T
136}
137
138/************************************************************************/
142static struct city *check_city(int city_id, struct cm_parameter *parameter)
143{
144 struct city *pcity = game_city_by_number(city_id);
145 struct cm_parameter dummy;
146
147 if (!parameter) {
148 parameter = &dummy;
149 }
150
151 if (!pcity
152 || !cma_get_parameter(ATTR_CITY_CMA_PARAMETER, city_id, parameter)) {
153 return NULL;
154 }
155
158
159 return NULL;
160 }
161
162 return pcity;
163}
164
165/************************************************************************/
170 const struct cm_result *result)
171{
173 int city_radius_sq = city_map_radius_sq_get(pcity);
175 bool success;
176 struct tile *pcenter = city_tile(pcity);
177
180
183 stats.apply_result_ignored++;
184
185 return TRUE;
186 }
187
188 /* Do checks */
189 if (city_size_get(pcity) != cm_result_citizens(result)) {
190 log_error("apply_result_on_server(city %d=\"%s\") bad result!",
193 cm_print_result(result);
194
195 return FALSE;
196 }
197
198 stats.apply_result_applied++;
199
200 log_apply_result("apply_result_on_server(city %d=\"%s\")",
202
204
205 /* Remove all surplus workers */
207 ptile, idx, x, y) {
208 if (tile_worked(ptile) == pcity
209 && !result->worker_positions[idx]) {
210 log_apply_result("Removing worker at {%d,%d}.", x, y);
211
214 pcity->id, ptile->index);
215 if (first_request_id == 0) {
217 }
218 }
220
221 /* Change the excess non-default specialists to default. */
223 int i;
224
225 if (sp == DEFAULT_SPECIALIST) {
226 continue;
227 }
228
229 for (i = 0; i < pcity->specialists[sp] - result->specialists[sp]; i++) {
230 log_apply_result("Change specialist from %d to %d.",
234 if (first_request_id == 0) {
236 }
237 }
239
240 /* now all surplus people are DEFAULT_SPECIALIST */
241
242 /* Set workers */
243 /* FIXME: This code assumes that any toggled worker will turn into a
244 * DEFAULT_SPECIALIST! */
245 city_tile_iterate_skip_free_worked(&(wld.map), city_radius_sq, pcenter, ptile, idx,
246 x, y) {
247 if (NULL == tile_worked(ptile)
248 && result->worker_positions[idx]) {
249 log_apply_result("Putting worker at {%d,%d}.", x, y);
251
254 pcity->id, ptile->index);
255 if (first_request_id == 0) {
257 }
258 }
260
261 /* Set all specialists except DEFAULT_SPECIALIST (all the unchanged
262 * ones remain as DEFAULT_SPECIALIST). */
264 int i;
265
266 if (sp == DEFAULT_SPECIALIST) {
267 continue;
268 }
269
270 for (i = 0; i < result->specialists[sp] - pcity->specialists[sp]; i++) {
271 log_apply_result("Changing specialist from %d to %d.",
275 if (first_request_id == 0) {
277 }
278 }
280
282 /*
283 * If last_request is 0 no change request was send. But it also
284 * means that the results are different or the fc_results_are_equal()
285 * test at the start of the function would be true. So this
286 * means that the client has other results for the same
287 * allocation of citizen than the server. We just send a
288 * PACKET_CITY_REFRESH to bring them in sync.
289 */
292 stats.refresh_forced++;
293 }
294
296
297 if (last_request_id != 0) {
298 int city_id = pcity->id;
299
301 if (pcity != check_city(city_id, NULL)) {
302 log_verbose("apply_result_on_server(city %d) !check_city()!", city_id);
303 return FALSE;
304 }
305 }
306
307 /* Return. */
309
311 if (!success) {
313
314#if SHOW_APPLY_RESULT_ON_SERVER_ERRORS
315 log_error("apply_result_on_server(city %d=\"%s\") no match!",
317
318 log_test("apply_result_on_server(city %d=\"%s\") have:",
322
323 log_test("apply_result_on_server(city %d=\"%s\") want:",
325 cm_print_result(result);
326#endif /* SHOW_APPLY_RESULT_ON_SERVER_ERRORS */
327 }
328
330
331 log_apply_result("apply_result_on_server() return %d.", (int) success);
332
333 return success;
334}
335
336/************************************************************************/
339static void report_stats(void)
340{
341#if SHOW_TIME_STATS
342 int total, per_mill;
343
344 total = stats.apply_result_ignored + stats.apply_result_applied;
345 per_mill = (stats.apply_result_ignored * 1000) / (total ? total : 1);
346
347 log_test("CMA: apply_result: ignored=%2d.%d%% (%d) "
348 "applied=%2d.%d%% (%d) total=%d",
349 per_mill / 10, per_mill % 10, stats.apply_result_ignored,
350 (1000 - per_mill) / 10, (1000 - per_mill) % 10,
351 stats.apply_result_applied, total);
352#endif /* SHOW_TIME_STATS */
353}
354
355/************************************************************************/
358static void release_city(int city_id)
359{
361}
362
363/****************************************************************************
364 Algorithmic functions
365****************************************************************************/
366
367/************************************************************************/
372static void handle_city(struct city *pcity)
373{
374 struct cm_result *result = cm_result_new(pcity);
375 bool handled;
376 int i, city_id = pcity->id;
377
378 log_handle_city("handle_city(city %d=\"%s\") pos=(%d,%d) owner=%s",
381
382 log_handle_city2("START handle city %d=\"%s\"",
384
385 handled = FALSE;
386 for (i = 0; i < 5; i++) {
387 struct cm_parameter parameter;
388
389 log_handle_city2(" try %d", i);
390
391 if (pcity != check_city(city_id, &parameter)) {
392 handled = TRUE;
393 break;
394 }
395
396 cm_query_result(pcity, &parameter, result, FALSE);
397 if (!result->found_a_valid) {
398 log_handle_city2(" no valid found result");
399
401
403 _("The citizen governor can't fulfill the requirements "
404 "for %s. Passing back control."), city_link(pcity));
405 handled = TRUE;
406 break;
407 } else {
408 if (!apply_result_on_server(pcity, result)) {
409 log_handle_city2(" doesn't cleanly apply");
410 if (pcity == check_city(city_id, NULL) && i == 0) {
412 _("The citizen governor has gotten confused dealing "
413 "with %s. You may want to have a look."),
415 }
416 } else {
417 log_handle_city2(" ok");
418 /* Everything ok */
419 handled = TRUE;
420 break;
421 }
422 }
423 }
424
425 cm_result_destroy(result);
426
427 if (!handled) {
428 fc_assert_ret(pcity == check_city(city_id, NULL));
429 log_handle_city2(" not handled");
430
432 _("The citizen governor has gotten confused dealing "
433 "with %s. You may want to have a look."),
435
437
438 bugreport_request("handle_city() CMA: %s has changed multiple times.",
440 }
441
442 log_handle_city2("END handle city=(%d)", city_id);
443}
444
445/************************************************************************/
448static void city_changed(int city_id)
449{
450 struct city *pcity = game_city_by_number(city_id);
451
452 if (pcity) {
455 }
456}
457
458/************************************************************************/
461static void city_remove(int city_id)
462{
463 release_city(city_id);
464}
465
466/************************************************************************/
469static void new_turn(void)
470{
471 report_stats();
472}
473
474/*************************** public interface ******************************/
475/************************************************************************/
478void cma_init(void)
479{
480 struct agent self;
481 struct timer *timer = stats.wall_timer;
482
483 log_debug("sizeof(struct cm_result)=%d",
484 (unsigned int) sizeof(struct cm_result));
485 log_debug("sizeof(struct cm_parameter)=%d",
486 (unsigned int) sizeof(struct cm_parameter));
487
488 /* reset cache counters */
489 memset(&stats, 0, sizeof(stats));
490
491 /* We used to just use timer_new() here, but apparently cma_init() can be
492 * called multiple times per client invocation so that lead to memory
493 * leaks. */
495 timer != NULL ? NULL : "agent: stats");
496
497 memset(&self, 0, sizeof(self));
498 strcpy(self.name, "CMA");
499 self.level = 1;
500 self.city_callbacks[CB_CHANGE] = city_changed;
501 self.city_callbacks[CB_NEW] = city_changed;
502 self.city_callbacks[CB_REMOVE] = city_remove;
503 self.turn_start_notify = new_turn;
505}
506
507/************************************************************************/
510bool cma_apply_result(struct city *pcity, const struct cm_result *result)
511{
513
514 if (result->found_a_valid) {
515 return apply_result_on_server(pcity, result);
516 } else {
517 return TRUE; /* ???????? */
518 }
519}
520
521/************************************************************************/
525 const struct cm_parameter *const parameter)
526{
527 log_debug("cma_put_city_under_agent(city %d=\"%s\")",
529
531
533
535
536 log_debug("cma_put_city_under_agent: return");
537}
538
539/************************************************************************/
548
549/************************************************************************/
553 struct cm_parameter *parameter)
554{
556
558 return FALSE;
559 }
560
561 if (parameter != NULL) {
562 memcpy(parameter, &my_parameter, sizeof(struct cm_parameter));
563 }
564
565 return TRUE;
566}
567
568/************************************************************************/
575bool cma_get_parameter(enum attr_city attr, int city_id,
576 struct cm_parameter *parameter)
577{
578 size_t len;
580 struct data_in din;
581 int version, dummy;
582
583 /* Changing this function is likely to break compatibility with old
584 * savegames that store these values. */
585
586 len = attr_city_get(attr, city_id, sizeof(buffer), buffer);
587 if (len == 0) {
588 return FALSE;
589 }
591 FALSE);
592
593 dio_input_init(&din, buffer, len);
594
595 dio_get_uint8_raw(&din, &version);
596 if (version > CMA_ATTR_VERSION && version < CMA_ATTR_VERSION_MIN_SUPPORTED) {
597 log_error("CMA data has a wrong version %d (expected %d)",
598 version, CMA_ATTR_VERSION);
599 return FALSE;
600 }
601
602 /* Initialize the parameter (includes some AI-only fields that aren't
603 * touched below). */
604 cm_init_parameter(parameter);
605
607 dio_get_sint16_raw(&din, &parameter->minimal_surplus[i]);
608 dio_get_sint16_raw(&din, &parameter->factor[i]);
610
611 dio_get_sint16_raw(&din, &parameter->happy_factor);
612 dio_get_uint8_raw(&din, &dummy); /* Dummy value; used to be factor_target. */
613 dio_get_bool8_raw(&din, &parameter->require_happy);
614 if (version > 2) {
615 dio_get_bool8_raw(&din, &parameter->max_growth);
616 }
617
618 return TRUE;
619}
620
621/************************************************************************/
624void cma_set_parameter(enum attr_city attr, int city_id,
625 const struct cm_parameter *parameter)
626{
627 char buffer[SAVED_PARAMETER_SIZE];
628 struct raw_data_out dout;
629
630 /* Changing this function is likely to break compatibility with old
631 * savegames that store these values. */
632
633 dio_output_init(&dout, buffer, sizeof(buffer));
634
636
639 dio_put_sint16_raw(&dout, parameter->factor[i]);
641
643 dio_put_uint8_raw(&dout, 0); /* Dummy value; used to be factor_target. */
645 dio_put_bool8_raw(&dout, parameter->max_growth);
646
648
649 attr_city_set(attr, city_id, SAVED_PARAMETER_SIZE, buffer);
650}
void wait_for_requests(const char *agent_name, int first_request_id, int last_request_id)
Definition agents.c:740
void cause_a_city_changed_for_agent(const char *name_of_calling_agent, struct city *pcity)
Definition agents.c:791
void register_agent(const struct agent *agent)
Definition agents.c:382
@ CB_NEW
Definition agents.h:37
@ CB_REMOVE
Definition agents.h:37
@ CB_CHANGE
Definition agents.h:37
size_t attr_city_get(enum attr_city what, int city_id, size_t max_data_length, void *data)
Definition attribute.c:498
void attr_city_set(enum attr_city what, int city_id, size_t data_length, const void *const data)
Definition attribute.c:489
attr_city
Definition attribute.h:37
@ ATTR_CITY_CMA_PARAMETER
Definition attribute.h:38
void bugreport_request(const char *reason_format,...)
Definition bugs.c:31
const char * city_name_get(const struct city *pcity)
Definition city.c:1137
int city_map_radius_sq_get(const struct city *pcity)
Definition city.c:137
bool city_can_work_tile(const struct city *pcity, const struct tile *ptile)
Definition city.c:1456
#define city_tile(_pcity_)
Definition city.h:561
static citizens city_size_get(const struct city *pcity)
Definition city.h:566
#define city_tile_iterate_skip_free_worked(_nmap, _radius_sq, _city_tile, _tile, _index, _x, _y)
Definition city.h:211
#define output_type_iterate(output)
Definition city.h:842
#define city_owner(_pcity_)
Definition city.h:560
#define city_tile_iterate_skip_free_worked_end
Definition city.h:219
#define city_map_iterate_end
Definition city.h:174
#define city_map_iterate(_radius_sq, _index, _x, _y)
Definition city.h:170
#define is_free_worked_index(city_tile_index)
Definition city.h:877
#define output_type_iterate_end
Definition city.h:848
int city_change_specialist(struct city *pcity, Specialist_type_id from, Specialist_type_id to)
void refresh_city_dialog(struct city *pcity)
void city_report_dialog_update_city(struct city *pcity)
static struct ai_type * self
Definition classicai.c:46
struct civclient client
void create_event(struct tile *ptile, enum event_type event, const struct ft_color color, const char *format,...)
Definition climisc.c:1093
void cm_clear_cache(struct city *pcity)
Definition cm.c:322
void cm_init_parameter(struct cm_parameter *dest)
Definition cm.c:2183
struct cm_result * cm_result_new(struct city *pcity)
Definition cm.c:345
void cm_result_from_main_map(struct cm_result *result, const struct city *pcity)
Definition cm.c:2261
void cm_result_destroy(struct cm_result *result)
Definition cm.c:368
void cm_print_result(const struct cm_result *result)
Definition cm.c:2469
void cm_query_result(struct city *pcity, const struct cm_parameter *param, struct cm_result *result, bool negative_ok)
Definition cm.c:2122
int cm_result_citizens(const struct cm_result *result)
Definition cm.c:2252
void cm_print_city(const struct city *pcity)
Definition cm.c:2431
#define ALWAYS_APPLY_AT_SERVER
Definition cma_core.c:80
int refresh_forced
Definition cma_core.c:93
#define T(x)
#define log_handle_city
Definition cma_core.c:74
static struct city * check_city(int city_id, struct cm_parameter *parameter)
Definition cma_core.c:142
#define CMA_ATTR_VERSION_MIN_SUPPORTED
Definition cma_core.c:86
static void report_stats(void)
Definition cma_core.c:339
#define SAVED_PARAMETER_SIZE
Definition cma_core.c:82
#define log_results_are_equal
Definition cma_core.c:76
#define log_handle_city2
Definition cma_core.c:75
static struct @132 stats
bool cma_is_city_under_agent(const struct city *pcity, struct cm_parameter *parameter)
Definition cma_core.c:552
static void city_changed(int city_id)
Definition cma_core.c:448
int apply_result_ignored
Definition cma_core.c:93
static void release_city(int city_id)
Definition cma_core.c:358
struct timer * wall_timer
Definition cma_core.c:92
void cma_put_city_under_agent(struct city *pcity, const struct cm_parameter *const parameter)
Definition cma_core.c:524
static void city_remove(int city_id)
Definition cma_core.c:461
static void new_turn(void)
Definition cma_core.c:469
static void handle_city(struct city *pcity)
Definition cma_core.c:372
int apply_result_applied
Definition cma_core.c:93
bool cma_get_parameter(enum attr_city attr, int city_id, struct cm_parameter *parameter)
Definition cma_core.c:575
static bool apply_result_on_server(struct city *pcity, const struct cm_result *result)
Definition cma_core.c:169
static bool fc_results_are_equal(const struct cm_result *result1, const struct cm_result *result2)
Definition cma_core.c:100
void cma_release_city(struct city *pcity)
Definition cma_core.c:542
#define CMA_ATTR_VERSION
Definition cma_core.c:85
void cma_set_parameter(enum attr_city attr, int city_id, const struct cm_parameter *parameter)
Definition cma_core.c:624
bool cma_apply_result(struct city *pcity, const struct cm_result *result)
Definition cma_core.c:510
#define log_apply_result
Definition cma_core.c:73
#define SAVED_PARAMETER_SIZE_OLD
Definition cma_core.c:83
void cma_init(void)
Definition cma_core.c:478
char * incite_cost
Definition comments.c:76
void connection_do_buffer(struct connection *pc)
Definition connection.c:324
void connection_do_unbuffer(struct connection *pc)
Definition connection.c:336
int dio_put_uint8_raw(struct raw_data_out *dout, int value)
Definition dataio_raw.c:265
void dio_output_init(struct raw_data_out *dout, void *destination, size_t dest_size)
Definition dataio_raw.c:171
bool dio_get_sint16_raw(struct data_in *din, int *dest)
Definition dataio_raw.c:777
int dio_put_bool8_raw(struct raw_data_out *dout, bool value)
Definition dataio_raw.c:386
bool dio_get_uint8_raw(struct data_in *din, int *dest)
Definition dataio_raw.c:598
bool dio_get_bool8_raw(struct data_in *din, bool *dest)
Definition dataio_raw.c:687
size_t dio_output_used(struct raw_data_out *dout)
Definition dataio_raw.c:184
void dio_input_init(struct data_in *din, const void *src, size_t src_size)
Definition dataio_raw.c:202
int dio_put_sint16_raw(struct raw_data_out *dout, int value)
Definition dataio_raw.c:366
struct unit struct city struct unit struct tile struct extra_type const struct act_prob *act_probs int actor_unit_id struct unit struct unit int const struct action *paction struct unit struct city * pcity
Definition dialogs_g.h:78
#define _(String)
Definition fcintl.h:67
const struct ft_color ftc_client
const char * city_link(const struct city *pcity)
struct world wld
Definition game.c:62
struct city * game_city_by_number(int id)
Definition game.c:106
#define fc_assert_ret(condition)
Definition log.h:192
#define log_test
Definition log.h:137
#define log_verbose(message,...)
Definition log.h:110
#define fc_assert(condition)
Definition log.h:177
#define fc_assert_ret_val(condition, val)
Definition log.h:195
#define fc_assert_action(condition, action)
Definition log.h:188
#define log_debug(message,...)
Definition log.h:116
#define log_error(message,...)
Definition log.h:104
const char * nation_rule_name(const struct nation_type *pnation)
Definition nation.c:138
struct nation_type * nation_of_city(const struct city *pcity)
Definition nation.c:454
int dsend_packet_city_make_specialist(struct connection *pc, int city_id, int tile_id)
int dsend_packet_city_refresh(struct connection *pc, int city_id)
int dsend_packet_city_make_worker(struct connection *pc, int city_id, int tile_id)
int len
Definition packhand.c:127
#define MAX(x, y)
Definition shared.h:54
struct specialist specialists[SP_MAX]
Definition specialist.c:30
#define specialist_type_iterate_end
Definition specialist.h:79
#define specialist_type_iterate(sp)
Definition specialist.h:73
#define DEFAULT_SPECIALIST
Definition specialist.h:43
struct sprite int int y
Definition sprite_g.h:31
struct sprite int x
Definition sprite_g.h:31
Definition agents.h:40
char name[MAX_LEN_NAME]
Definition ai.h:51
Definition city.h:317
struct connection conn
Definition client_main.h:96
int factor[O_LAST]
Definition cm.h:47
bool max_growth
Definition cm.h:42
bool require_happy
Definition cm.h:43
int minimal_surplus[O_LAST]
Definition cm.h:41
int happy_factor
Definition cm.h:48
Definition cm.h:52
bool found_a_valid
Definition cm.h:54
bool * worker_positions
Definition cm.h:59
citizens specialists[SP_MAX]
Definition cm.h:60
struct player * playing
Definition connection.h:151
Definition tile.h:50
Definition timing.c:81
int id
Definition unit.h:147
struct tile * tile
Definition unit.h:142
struct civ_map map
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
#define tile_worked(_tile)
Definition tile.h:115
#define TILE_XY(ptile)
Definition tile.h:43
struct timer * timer_renew(struct timer *t, enum timer_timetype type, enum timer_use use, const char *name)
Definition timing.c:180
@ TIMER_ACTIVE
Definition timing.h:46
@ TIMER_USER
Definition timing.h:42