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 "fcintl.h"
25 #include "log.h"
26 #include "mem.h"
27 #include "shared.h"             /* for MIN() */
28 #include "specialist.h"
29 #include "support.h"
30 #include "timing.h"
31 
32 /* common */
33 #include "city.h"
34 #include "dataio.h"
35 #include "events.h"
36 #include "game.h"
37 #include "government.h"
38 #include "packets.h"
39 #include "specialist.h"
40 
41 /* client */
42 #include "attribute.h"
43 #include "client_main.h"
44 #include "climisc.h"
45 #include "packhand.h"
46 
47 /* client/include */
48 #include "chatline_g.h"
49 #include "citydlg_g.h"
50 #include "cityrep_g.h"
51 #include "messagewin_g.h"
52 
53 /* client/agents */
54 #include "agents.h"
55 
56 #include "cma_core.h"
57 
58 
59 /*
60  * The CMA is an agent. The CMA will subscribe itself to all city
61  * events. So if a city changes the callback function city_changed is
62  * called. handle_city will be called from city_changed to update the
63  * given city. handle_city will call cma_query_result and
64  * apply_result_on_server to update the server city state.
65  */
66 
67 /****************************************************************************
68  defines, structs, globals, forward declarations
69 *****************************************************************************/
70 
71 #define log_apply_result                log_debug
72 #define log_handle_city                 log_debug
73 #define log_handle_city2                log_debug
74 #define log_results_are_equal           log_debug
75 
76 #define SHOW_TIME_STATS                                 FALSE
77 #define SHOW_APPLY_RESULT_ON_SERVER_ERRORS              FALSE
78 #define ALWAYS_APPLY_AT_SERVER                          FALSE
79 
80 #define SAVED_PARAMETER_SIZE				29
81 
82 #define CMA_ATTR_VERSION                                2
83 
84 /*
85  * Misc statistic to analyze performance.
86  */
87 static struct {
88   struct timer *wall_timer;
89   int apply_result_ignored, apply_result_applied, refresh_forced;
90 } stats;
91 
92 
93 /****************************************************************************
94  Returns TRUE iff the two results are equal. Both results have to be
95  results for the given city.
96 *****************************************************************************/
fc_results_are_equal(const struct cm_result * result1,const struct cm_result * result2)97 static bool fc_results_are_equal(const struct cm_result *result1,
98                                  const struct cm_result *result2)
99 {
100 #define T(x) if (result1->x != result2->x) { \
101   log_results_are_equal(#x); \
102   return FALSE; }
103 
104   T(disorder);
105   T(happy);
106 
107   specialist_type_iterate(sp) {
108     T(specialists[sp]);
109   } specialist_type_iterate_end;
110 
111   output_type_iterate(ot) {
112     T(surplus[ot]);
113   } output_type_iterate_end;
114 
115   fc_assert_ret_val(result1->city_radius_sq == result2->city_radius_sq,
116                     FALSE);
117   city_map_iterate(result1->city_radius_sq, cindex, x, y) {
118     if (is_free_worked_index(cindex)) {
119       continue;
120     }
121 
122     if (result1->worker_positions[cindex]
123         != result2->worker_positions[cindex]) {
124       log_results_are_equal("worker_positions");
125       return FALSE;
126     }
127   } city_map_iterate_end;
128 
129   return TRUE;
130 
131 #undef T
132 }
133 
134 
135 /****************************************************************************
136   Returns TRUE if the city is valid for CMA. Fills parameter if TRUE
137   is returned. Parameter can be NULL.
138 *****************************************************************************/
check_city(int city_id,struct cm_parameter * parameter)139 static struct city *check_city(int city_id, struct cm_parameter *parameter)
140 {
141   struct city *pcity = game_city_by_number(city_id);
142   struct cm_parameter dummy;
143 
144   if (!parameter) {
145     parameter = &dummy;
146   }
147 
148   if (!pcity
149       || !cma_get_parameter(ATTR_CITY_CMA_PARAMETER, city_id, parameter)) {
150     return NULL;
151   }
152 
153   if (city_owner(pcity) != client.conn.playing) {
154     cma_release_city(pcity);
155     return NULL;
156   }
157 
158   return pcity;
159 }
160 
161 /****************************************************************************
162  Change the actual city setting to the given result. Returns TRUE iff
163  the actual data matches the calculated one.
164 *****************************************************************************/
apply_result_on_server(struct city * pcity,const struct cm_result * result)165 static bool apply_result_on_server(struct city *pcity,
166                                    const struct cm_result *result)
167 {
168   int first_request_id = 0, last_request_id = 0, i;
169   int city_radius_sq = city_map_radius_sq_get(pcity);
170   struct cm_result *current_state = cm_result_new(pcity);;
171   bool success;
172   struct tile *pcenter = city_tile(pcity);
173 
174   fc_assert_ret_val(result->found_a_valid, FALSE);
175   cm_result_from_main_map(current_state, pcity);
176 
177   if (fc_results_are_equal(current_state, result)
178       && !ALWAYS_APPLY_AT_SERVER) {
179     stats.apply_result_ignored++;
180     return TRUE;
181   }
182 
183   /* Do checks */
184   if (city_size_get(pcity) != cm_result_citizens(result)) {
185     log_error("apply_result_on_server(city %d=\"%s\") bad result!",
186               pcity->id, city_name_get(pcity));
187     cm_print_city(pcity);
188     cm_print_result(result);
189     return FALSE;
190   }
191 
192   stats.apply_result_applied++;
193 
194   log_apply_result("apply_result_on_server(city %d=\"%s\")",
195                    pcity->id, city_name_get(pcity));
196 
197   connection_do_buffer(&client.conn);
198 
199   /* Remove all surplus workers */
200   city_tile_iterate_skip_free_worked(city_radius_sq, pcenter, ptile, idx,
201                                      x, y) {
202     if (tile_worked(ptile) == pcity
203         && !result->worker_positions[idx]) {
204       log_apply_result("Removing worker at {%d,%d}.", x, y);
205 
206       last_request_id =
207         dsend_packet_city_make_specialist(&client.conn, pcity->id, x, y);
208       if (first_request_id == 0) {
209         first_request_id = last_request_id;
210       }
211     }
212   } city_tile_iterate_skip_free_worked_end;
213 
214   /* Change the excess non-default specialists to default. */
215   specialist_type_iterate(sp) {
216     if (sp == DEFAULT_SPECIALIST) {
217       continue;
218     }
219 
220     for (i = 0; i < pcity->specialists[sp] - result->specialists[sp]; i++) {
221       log_apply_result("Change specialist from %d to %d.",
222                        sp, DEFAULT_SPECIALIST);
223       last_request_id = city_change_specialist(pcity,
224 					       sp, DEFAULT_SPECIALIST);
225       if (first_request_id == 0) {
226 	first_request_id = last_request_id;
227       }
228     }
229   } specialist_type_iterate_end;
230 
231   /* now all surplus people are DEFAULT_SPECIALIST */
232 
233   /* Set workers */
234   /* FIXME: This code assumes that any toggled worker will turn into a
235    * DEFAULT_SPECIALIST! */
236   city_tile_iterate_skip_free_worked(city_radius_sq, pcenter, ptile, idx,
237                                      x, y) {
238     if (NULL == tile_worked(ptile)
239      && result->worker_positions[idx]) {
240       log_apply_result("Putting worker at {%d,%d}.", x, y);
241       fc_assert_action(city_can_work_tile(pcity, ptile), break);
242 
243       last_request_id =
244         dsend_packet_city_make_worker(&client.conn, pcity->id, x, y);
245       if (first_request_id == 0) {
246 	first_request_id = last_request_id;
247       }
248     }
249   } city_tile_iterate_skip_free_worked_end;
250 
251   /* Set all specialists except DEFAULT_SPECIALIST (all the unchanged
252    * ones remain as DEFAULT_SPECIALIST). */
253   specialist_type_iterate(sp) {
254     if (sp == DEFAULT_SPECIALIST) {
255       continue;
256     }
257 
258     for (i = 0; i < result->specialists[sp] - pcity->specialists[sp]; i++) {
259       log_apply_result("Changing specialist from %d to %d.",
260                        DEFAULT_SPECIALIST, sp);
261       last_request_id = city_change_specialist(pcity,
262 					       DEFAULT_SPECIALIST, sp);
263       if (first_request_id == 0) {
264 	first_request_id = last_request_id;
265       }
266     }
267   } specialist_type_iterate_end;
268 
269   if (last_request_id == 0 || ALWAYS_APPLY_AT_SERVER) {
270       /*
271        * If last_request is 0 no change request was send. But it also
272        * means that the results are different or the fc_results_are_equal()
273        * test at the start of the function would be true. So this
274        * means that the client has other results for the same
275        * allocation of citizen than the server. We just send a
276        * PACKET_CITY_REFRESH to bring them in sync.
277        */
278     first_request_id = last_request_id =
279 	dsend_packet_city_refresh(&client.conn, pcity->id);
280     stats.refresh_forced++;
281   }
282 
283   connection_do_unbuffer(&client.conn);
284 
285   if (last_request_id != 0) {
286     int city_id = pcity->id;
287 
288     wait_for_requests("CMA", first_request_id, last_request_id);
289     if (pcity != check_city(city_id, NULL)) {
290       log_verbose("apply_result_on_server(city %d) !check_city()!", city_id);
291       return FALSE;
292     }
293   }
294 
295   /* Return. */
296   cm_result_from_main_map(current_state, pcity);
297 
298   success = fc_results_are_equal(current_state, result);
299   if (!success) {
300     cm_clear_cache(pcity);
301 
302 #if SHOW_APPLY_RESULT_ON_SERVER_ERRORS
303       log_error("apply_result_on_server(city %d=\"%s\") no match!",
304                 pcity->id, city_name_get(pcity));
305 
306       log_test("apply_result_on_server(city %d=\"%s\") have:",
307                pcity->id, city_name_get(pcity));
308       cm_print_city(pcity);
309       cm_print_result(current_state);
310 
311       log_test("apply_result_on_server(city %d=\"%s\") want:",
312                pcity->id, city_name_get(pcity));
313       cm_print_result(result);
314 #endif /* SHOW_APPLY_RESULT_ON_SERVER_ERRORS */
315   }
316 
317   cm_result_destroy(current_state);
318 
319   log_apply_result("apply_result_on_server() return %d.", (int) success);
320   return success;
321 }
322 
323 /****************************************************************************
324  Prints the data of the stats struct via log_test(...).
325 *****************************************************************************/
report_stats(void)326 static void report_stats(void)
327 {
328 #if SHOW_TIME_STATS
329   int total, per_mill;
330 
331   total = stats.apply_result_ignored + stats.apply_result_applied;
332   per_mill = (stats.apply_result_ignored * 1000) / (total ? total : 1);
333 
334   log_test("CMA: apply_result: ignored=%2d.%d%% (%d) "
335            "applied=%2d.%d%% (%d) total=%d",
336            per_mill / 10, per_mill % 10, stats.apply_result_ignored,
337            (1000 - per_mill) / 10, (1000 - per_mill) % 10,
338            stats.apply_result_applied, total);
339 #endif /* SHOW_TIME_STATS */
340 }
341 
342 /****************************************************************************
343   Remove governor setting from city.
344 *****************************************************************************/
release_city(int city_id)345 static void release_city(int city_id)
346 {
347   attr_city_set(ATTR_CITY_CMA_PARAMETER, city_id, 0, NULL);
348 }
349 
350 /****************************************************************************
351                            algorithmic functions
352 *****************************************************************************/
353 
354 /****************************************************************************
355  The given city has changed. handle_city ensures that either the city
356  follows the set CMA goal or that the CMA detaches itself from the
357  city.
358 *****************************************************************************/
handle_city(struct city * pcity)359 static void handle_city(struct city *pcity)
360 {
361   struct cm_result *result = cm_result_new(pcity);
362   bool handled;
363   int i, city_id = pcity->id;
364 
365   log_handle_city("handle_city(city %d=\"%s\") pos=(%d,%d) owner=%s",
366                   pcity->id, city_name_get(pcity), TILE_XY(pcity->tile),
367                   nation_rule_name(nation_of_city(pcity)));
368 
369   log_handle_city2("START handle city %d=\"%s\"",
370                    pcity->id, city_name_get(pcity));
371 
372   handled = FALSE;
373   for (i = 0; i < 5; i++) {
374     struct cm_parameter parameter;
375 
376     log_handle_city2("  try %d", i);
377 
378     if (pcity != check_city(city_id, &parameter)) {
379       handled = TRUE;
380       break;
381     }
382 
383     cm_query_result(pcity, &parameter, result, FALSE);
384     if (!result->found_a_valid) {
385       log_handle_city2("  no valid found result");
386 
387       cma_release_city(pcity);
388 
389       create_event(city_tile(pcity), E_CITY_CMA_RELEASE, ftc_client,
390                    _("The citizen governor can't fulfill the requirements "
391                      "for %s. Passing back control."), city_link(pcity));
392       handled = TRUE;
393       break;
394     } else {
395       if (!apply_result_on_server(pcity, result)) {
396         log_handle_city2("  doesn't cleanly apply");
397         if (pcity == check_city(city_id, NULL) && i == 0) {
398           create_event(city_tile(pcity), E_CITY_CMA_RELEASE, ftc_client,
399                        _("The citizen governor has gotten confused dealing "
400                          "with %s.  You may want to have a look."),
401                        city_link(pcity));
402         }
403       } else {
404         log_handle_city2("  ok");
405         /* Everything ok */
406         handled = TRUE;
407         break;
408       }
409     }
410   }
411 
412   cm_result_destroy(result);
413 
414   if (!handled) {
415     fc_assert_ret(pcity == check_city(city_id, NULL));
416     log_handle_city2("  not handled");
417 
418     create_event(city_tile(pcity), E_CITY_CMA_RELEASE, ftc_client,
419                  _("The citizen governor has gotten confused dealing "
420                    "with %s.  You may want to have a look."),
421                  city_link(pcity));
422 
423     cma_release_city(pcity);
424 
425     log_error("handle_city() CMA: %s has changed multiple times.",
426               city_name_get(pcity));
427     /* TRANS: No full stop after the URL, could cause confusion. */
428     log_error(_("Please report this message at %s"), BUG_URL);
429   }
430 
431   log_handle_city2("END handle city=(%d)", city_id);
432 }
433 
434 /****************************************************************************
435  Callback for the agent interface.
436 *****************************************************************************/
city_changed(int city_id)437 static void city_changed(int city_id)
438 {
439   struct city *pcity = game_city_by_number(city_id);
440 
441   if (pcity) {
442     cm_clear_cache(pcity);
443     handle_city(pcity);
444   }
445 }
446 
447 /****************************************************************************
448  Callback for the agent interface.
449 *****************************************************************************/
city_remove(int city_id)450 static void city_remove(int city_id)
451 {
452   release_city(city_id);
453 }
454 
455 /****************************************************************************
456  Callback for the agent interface.
457 *****************************************************************************/
new_turn(void)458 static void new_turn(void)
459 {
460   report_stats();
461 }
462 
463 /*************************** public interface *******************************/
464 /****************************************************************************
465   Initialize city governor code
466 *****************************************************************************/
cma_init(void)467 void cma_init(void)
468 {
469   struct agent self;
470   struct timer *timer = stats.wall_timer;
471 
472   log_debug("sizeof(struct cm_result)=%d",
473             (unsigned int) sizeof(struct cm_result));
474   log_debug("sizeof(struct cm_parameter)=%d",
475             (unsigned int) sizeof(struct cm_parameter));
476 
477   /* reset cache counters */
478   memset(&stats, 0, sizeof(stats));
479 
480   /* We used to just use timer_new here, but apparently cma_init can be
481    * called multiple times per client invocation so that lead to memory
482    * leaks. */
483   stats.wall_timer = timer_renew(timer, TIMER_USER, TIMER_ACTIVE);
484 
485   memset(&self, 0, sizeof(self));
486   strcpy(self.name, "CMA");
487   self.level = 1;
488   self.city_callbacks[CB_CHANGE] = city_changed;
489   self.city_callbacks[CB_NEW] = city_changed;
490   self.city_callbacks[CB_REMOVE] = city_remove;
491   self.turn_start_notify = new_turn;
492   register_agent(&self);
493 }
494 
495 /****************************************************************************
496   Apply result on server if it's valid
497 *****************************************************************************/
cma_apply_result(struct city * pcity,const struct cm_result * result)498 bool cma_apply_result(struct city *pcity, const struct cm_result *result)
499 {
500   fc_assert(!cma_is_city_under_agent(pcity, NULL));
501   if (result->found_a_valid) {
502     return apply_result_on_server(pcity, result);
503   } else
504     return TRUE; /* ???????? */
505 }
506 
507 /****************************************************************************
508   Put city under governor control
509 *****************************************************************************/
cma_put_city_under_agent(struct city * pcity,const struct cm_parameter * const parameter)510 void cma_put_city_under_agent(struct city *pcity,
511                               const struct cm_parameter *const parameter)
512 {
513   log_debug("cma_put_city_under_agent(city %d=\"%s\")",
514             pcity->id, city_name_get(pcity));
515 
516   fc_assert_ret(city_owner(pcity) == client.conn.playing);
517 
518   cma_set_parameter(ATTR_CITY_CMA_PARAMETER, pcity->id, parameter);
519 
520   cause_a_city_changed_for_agent("CMA", pcity);
521 
522   log_debug("cma_put_city_under_agent: return");
523 }
524 
525 /****************************************************************************
526   Release city from governor control.
527 *****************************************************************************/
cma_release_city(struct city * pcity)528 void cma_release_city(struct city *pcity)
529 {
530   release_city(pcity->id);
531   refresh_city_dialog(pcity);
532   city_report_dialog_update_city(pcity);
533 }
534 
535 /****************************************************************************
536   Check whether city is under governor control, and fill parameter if it is.
537 *****************************************************************************/
cma_is_city_under_agent(const struct city * pcity,struct cm_parameter * parameter)538 bool cma_is_city_under_agent(const struct city *pcity,
539 			     struct cm_parameter *parameter)
540 {
541   struct cm_parameter my_parameter;
542 
543   if (!cma_get_parameter(ATTR_CITY_CMA_PARAMETER, pcity->id, &my_parameter)) {
544     return FALSE;
545   }
546 
547   if (parameter) {
548     memcpy(parameter, &my_parameter, sizeof(struct cm_parameter));
549   }
550   return TRUE;
551 }
552 
553 /**************************************************************************
554   Get the parameter.
555 
556   Don't bother to cm_init_parameter, since we set all the fields anyway.
557   But leave the comment here so we can find this place when searching
558   for all the creators of a parameter.
559 **************************************************************************/
cma_get_parameter(enum attr_city attr,int city_id,struct cm_parameter * parameter)560 bool cma_get_parameter(enum attr_city attr, int city_id,
561 		       struct cm_parameter *parameter)
562 {
563   size_t len;
564   char buffer[SAVED_PARAMETER_SIZE];
565   struct data_in din;
566   int version, dummy;
567 
568   /* Changing this function is likely to break compatibility with old
569    * savegames that store these values. */
570 
571   len = attr_city_get(attr, city_id, sizeof(buffer), buffer);
572   if (len == 0) {
573     return FALSE;
574   }
575   fc_assert_ret_val(len == SAVED_PARAMETER_SIZE, FALSE);
576 
577   dio_input_init(&din, buffer, len);
578 
579   dio_get_uint8(&din, &version);
580   if (version != CMA_ATTR_VERSION) {
581     log_error("CMA data has a wrong version %d (expected %d)",
582               version, CMA_ATTR_VERSION);
583     return FALSE;
584   }
585 
586   /* Initialize the parameter (includes some AI-only fields that aren't
587    * touched below). */
588   cm_init_parameter(parameter);
589 
590   output_type_iterate(i) {
591     dio_get_sint16(&din, &parameter->minimal_surplus[i]);
592     dio_get_sint16(&din, &parameter->factor[i]);
593   } output_type_iterate_end;
594 
595   dio_get_sint16(&din, &parameter->happy_factor);
596   dio_get_uint8(&din, &dummy); /* Dummy value; used to be factor_target. */
597   dio_get_bool8(&din, &parameter->require_happy);
598 
599   return TRUE;
600 }
601 
602 /**************************************************************************
603   Set attribute block for city from parameter.
604 **************************************************************************/
cma_set_parameter(enum attr_city attr,int city_id,const struct cm_parameter * parameter)605 void cma_set_parameter(enum attr_city attr, int city_id,
606 		       const struct cm_parameter *parameter)
607 {
608   char buffer[SAVED_PARAMETER_SIZE];
609   struct data_out dout;
610 
611   /* Changing this function is likely to break compatibility with old
612    * savegames that store these values. */
613 
614   dio_output_init(&dout, buffer, sizeof(buffer));
615 
616   dio_put_uint8(&dout, CMA_ATTR_VERSION);
617 
618   output_type_iterate(i) {
619     dio_put_sint16(&dout, parameter->minimal_surplus[i]);
620     dio_put_sint16(&dout, parameter->factor[i]);
621   } output_type_iterate_end;
622 
623   dio_put_sint16(&dout, parameter->happy_factor);
624   dio_put_uint8(&dout, 0); /* Dummy value; used to be factor_target. */
625   dio_put_bool8(&dout, parameter->require_happy);
626 
627   fc_assert(dio_output_used(&dout) == SAVED_PARAMETER_SIZE);
628 
629   attr_city_set(attr, city_id, SAVED_PARAMETER_SIZE, buffer);
630 }
631