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
84#define CMA_ATTR_VERSION 3
85#define CMA_ATTR_VERSION_MIN_SUPPORTED 2
86
87/*
88 * Misc statistic to analyze performance.
89 */
90static struct {
94
95/************************************************************************/
99static bool fc_results_are_equal(const struct cm_result *result1,
100 const struct cm_result *result2)
101{
102#define T(x) if (result1->x != result2->x) { \
103 log_results_are_equal(#x); \
104 return FALSE; }
105
106 T(disorder);
107 T(happy);
108
110 T(specialists[sp]);
112
114 T(surplus[ot]);
116
117 fc_assert_ret_val(result1->city_radius_sq == result2->city_radius_sq,
118 FALSE);
119 city_map_iterate(result1->city_radius_sq, cindex, x, y) {
120 if (is_free_worked_index(cindex)) {
121 continue;
122 }
123
124 if (result1->worker_positions[cindex]
125 != result2->worker_positions[cindex]) {
126 log_results_are_equal("worker_positions");
127
128 return FALSE;
129 }
131
132 return TRUE;
133
134#undef T
135}
136
137/************************************************************************/
141static struct city *check_city(int city_id, struct cm_parameter *parameter)
142{
143 struct city *pcity = game_city_by_number(city_id);
144 struct cm_parameter dummy;
145
146 if (!parameter) {
147 parameter = &dummy;
148 }
149
150 if (!pcity
151 || !cma_get_parameter(ATTR_CITY_CMA_PARAMETER, city_id, parameter)) {
152 return NULL;
153 }
154
155 if (city_owner(pcity) != client.conn.playing) {
156 cma_release_city(pcity);
157
158 return NULL;
159 }
160
161 return pcity;
162}
163
164/************************************************************************/
168static bool apply_result_on_server(struct city *pcity,
169 const struct cm_result *result)
170{
172 int city_radius_sq = city_map_radius_sq_get(pcity);
173 struct cm_result *current_state = cm_result_new(pcity);
174 bool success;
175 struct tile *pcenter = city_tile(pcity);
176
179
182 stats.apply_result_ignored++;
183
184 return TRUE;
185 }
186
187 /* Do checks */
188 if (city_size_get(pcity) != cm_result_citizens(result)) {
189 log_error("apply_result_on_server(city %d=\"%s\") bad result!",
190 pcity->id, city_name_get(pcity));
191 cm_print_city(pcity);
192 cm_print_result(result);
193
194 return FALSE;
195 }
196
197 stats.apply_result_applied++;
198
199 log_apply_result("apply_result_on_server(city %d=\"%s\")",
200 pcity->id, city_name_get(pcity));
201
203
204 /* Remove all surplus workers */
206 ptile, idx, x, y) {
207 if (tile_worked(ptile) == pcity
208 && !result->worker_positions[idx]) {
209 log_apply_result("Removing worker at {%d,%d}.", x, y);
210
213 pcity->id, ptile->index);
214 if (first_request_id == 0) {
216 }
217 }
219
220 /* Change the excess non-default specialists to default. */
222 int i;
223
224 if (sp == DEFAULT_SPECIALIST) {
225 continue;
226 }
227
228 for (i = 0; i < pcity->specialists[sp] - result->specialists[sp]; i++) {
229 log_apply_result("Change specialist from %d to %d.",
233 if (first_request_id == 0) {
235 }
236 }
238
239 /* now all surplus people are DEFAULT_SPECIALIST */
240
241 /* Set workers */
242 /* FIXME: This code assumes that any toggled worker will turn into a
243 * DEFAULT_SPECIALIST! */
244 city_tile_iterate_skip_free_worked(&(wld.map), city_radius_sq, pcenter, ptile, idx,
245 x, y) {
246 if (NULL == tile_worked(ptile)
247 && result->worker_positions[idx]) {
248 log_apply_result("Putting worker at {%d,%d}.", x, y);
249 fc_assert_action(city_can_work_tile(pcity, ptile), break);
250
253 pcity->id, ptile->index);
254 if (first_request_id == 0) {
256 }
257 }
259
260 /* Set all specialists except DEFAULT_SPECIALIST (all the unchanged
261 * ones remain as DEFAULT_SPECIALIST). */
263 int i;
264
265 if (sp == DEFAULT_SPECIALIST) {
266 continue;
267 }
268
269 for (i = 0; i < result->specialists[sp] - pcity->specialists[sp]; i++) {
270 log_apply_result("Changing specialist from %d to %d.",
274 if (first_request_id == 0) {
276 }
277 }
279
281 /*
282 * If last_request is 0 no change request was send. But it also
283 * means that the results are different or the fc_results_are_equal()
284 * test at the start of the function would be true. So this
285 * means that the client has other results for the same
286 * allocation of citizen than the server. We just send a
287 * PACKET_CITY_REFRESH to bring them in sync.
288 */
291 stats.refresh_forced++;
292 }
293
295
296 if (last_request_id != 0) {
297 int city_id = pcity->id;
298
300 if (pcity != check_city(city_id, NULL)) {
301 log_verbose("apply_result_on_server(city %d) !check_city()!", city_id);
302 return FALSE;
303 }
304 }
305
306 /* Return. */
308
310 if (!success) {
311 cm_clear_cache(pcity);
312
313#if SHOW_APPLY_RESULT_ON_SERVER_ERRORS
314 log_error("apply_result_on_server(city %d=\"%s\") no match!",
315 pcity->id, city_name_get(pcity));
316
317 log_test("apply_result_on_server(city %d=\"%s\") have:",
318 pcity->id, city_name_get(pcity));
319 cm_print_city(pcity);
321
322 log_test("apply_result_on_server(city %d=\"%s\") want:",
323 pcity->id, city_name_get(pcity));
324 cm_print_result(result);
325#endif /* SHOW_APPLY_RESULT_ON_SERVER_ERRORS */
326 }
327
329
330 log_apply_result("apply_result_on_server() return %d.", (int) success);
331
332 return success;
333}
334
335/************************************************************************/
338static void report_stats(void)
339{
340#if SHOW_TIME_STATS
341 int total, per_mill;
342
343 total = stats.apply_result_ignored + stats.apply_result_applied;
344 per_mill = (stats.apply_result_ignored * 1000) / (total ? total : 1);
345
346 log_test("CMA: apply_result: ignored=%2d.%d%% (%d) "
347 "applied=%2d.%d%% (%d) total=%d",
348 per_mill / 10, per_mill % 10, stats.apply_result_ignored,
349 (1000 - per_mill) / 10, (1000 - per_mill) % 10,
350 stats.apply_result_applied, total);
351#endif /* SHOW_TIME_STATS */
352}
353
354/************************************************************************/
357static void release_city(int city_id)
358{
360}
361
362/****************************************************************************
363 Algorithmic functions
364****************************************************************************/
365
366/************************************************************************/
371static void handle_city(struct city *pcity)
372{
373 struct cm_result *result = cm_result_new(pcity);
374 bool handled;
375 int i, city_id = pcity->id;
376
377 log_handle_city("handle_city(city %d=\"%s\") pos=(%d,%d) owner=%s",
378 pcity->id, city_name_get(pcity), TILE_XY(pcity->tile),
380
381 log_handle_city2("START handle city %d=\"%s\"",
382 pcity->id, city_name_get(pcity));
383
384 handled = FALSE;
385 for (i = 0; i < 5; i++) {
386 struct cm_parameter parameter;
387
388 log_handle_city2(" try %d", i);
389
390 if (pcity != check_city(city_id, &parameter)) {
391 handled = TRUE;
392 break;
393 }
394
395 cm_query_result(pcity, &parameter, result, FALSE);
396 if (!result->found_a_valid) {
397 log_handle_city2(" no valid found result");
398
399 cma_release_city(pcity);
400
402 _("The citizen governor can't fulfill the requirements "
403 "for %s. Passing back control."), city_link(pcity));
404 handled = TRUE;
405 break;
406 } else {
407 if (!apply_result_on_server(pcity, result)) {
408 log_handle_city2(" doesn't cleanly apply");
409 if (pcity == check_city(city_id, NULL) && i == 0) {
411 _("The citizen governor has gotten confused dealing "
412 "with %s. You may want to have a look."),
413 city_link(pcity));
414 }
415 } else {
416 log_handle_city2(" ok");
417 /* Everything ok */
418 handled = TRUE;
419 break;
420 }
421 }
422 }
423
424 cm_result_destroy(result);
425
426 if (!handled) {
427 fc_assert_ret(pcity == check_city(city_id, NULL));
428 log_handle_city2(" not handled");
429
431 _("The citizen governor has gotten confused dealing "
432 "with %s. You may want to have a look."),
433 city_link(pcity));
434
435 cma_release_city(pcity);
436
437 bugreport_request("handle_city() CMA: %s has changed multiple times.",
438 city_name_get(pcity));
439 }
440
441 log_handle_city2("END handle city=(%d)", city_id);
442}
443
444/************************************************************************/
447static void city_changed(int city_id)
448{
449 struct city *pcity = game_city_by_number(city_id);
450
451 if (pcity) {
452 cm_clear_cache(pcity);
453 handle_city(pcity);
454 }
455}
456
457/************************************************************************/
460static void city_remove(int city_id)
461{
462 release_city(city_id);
463}
464
465/************************************************************************/
468static void new_turn(void)
469{
470 report_stats();
471}
472
473/*************************** public interface ******************************/
474/************************************************************************/
477void cma_init(void)
478{
479 struct agent self;
480 struct timer *timer = stats.wall_timer;
481
482 log_debug("sizeof(struct cm_result)=%d",
483 (unsigned int) sizeof(struct cm_result));
484 log_debug("sizeof(struct cm_parameter)=%d",
485 (unsigned int) sizeof(struct cm_parameter));
486
487 /* reset cache counters */
488 memset(&stats, 0, sizeof(stats));
489
490 /* We used to just use timer_new() here, but apparently cma_init() can be
491 * called multiple times per client invocation so that lead to memory
492 * leaks. */
494 timer != NULL ? NULL : "agent: stats");
495
496 memset(&self, 0, sizeof(self));
497 strcpy(self.name, "CMA");
498 self.level = 1;
499 self.city_callbacks[CB_CHANGE] = city_changed;
500 self.city_callbacks[CB_NEW] = city_changed;
501 self.city_callbacks[CB_REMOVE] = city_remove;
502 self.turn_start_notify = new_turn;
504}
505
506/************************************************************************/
509bool cma_apply_result(struct city *pcity, const struct cm_result *result)
510{
512
513 if (result->found_a_valid) {
514 return apply_result_on_server(pcity, result);
515 } else {
516 return TRUE; /* ???????? */
517 }
518}
519
520/************************************************************************/
524 const struct cm_parameter *const parameter)
525{
526 log_debug("cma_put_city_under_agent(city %d=\"%s\")",
527 pcity->id, city_name_get(pcity));
528
530
531 cma_set_parameter(ATTR_CITY_CMA_PARAMETER, pcity->id, parameter);
532
533 cause_a_city_changed_for_agent("CMA", pcity);
534
535 log_debug("cma_put_city_under_agent: return");
536}
537
538/************************************************************************/
541void cma_release_city(struct city *pcity)
542{
543 release_city(pcity->id);
544 refresh_city_dialog(pcity);
546}
547
548/************************************************************************/
551bool cma_is_city_under_agent(const struct city *pcity,
552 struct cm_parameter *parameter)
553{
555
557 return FALSE;
558 }
559
560 if (parameter != NULL) {
561 memcpy(parameter, &my_parameter, sizeof(struct cm_parameter));
562 }
563
564 return TRUE;
565}
566
567/************************************************************************/
574bool cma_get_parameter(enum attr_city attr, int city_id,
575 struct cm_parameter *parameter)
576{
577 size_t len;
578 char buffer[SAVED_PARAMETER_SIZE];
579 struct data_in din;
580 int version, dummy;
581
582 /* Changing this function is likely to break compatibility with old
583 * savegames that store these values. */
584
585 len = attr_city_get(attr, city_id, sizeof(buffer), buffer);
586 if (len == 0) {
587 return FALSE;
588 }
590
591 dio_input_init(&din, buffer, len);
592
593 dio_get_uint8_raw(&din, &version);
594 if (version > CMA_ATTR_VERSION && version < CMA_ATTR_VERSION_MIN_SUPPORTED) {
595 log_error("CMA data has a wrong version %d (expected %d)",
596 version, CMA_ATTR_VERSION);
597 return FALSE;
598 }
599
600 /* Initialize the parameter (includes some AI-only fields that aren't
601 * touched below). */
602 cm_init_parameter(parameter);
603
605 dio_get_sint16_raw(&din, &parameter->minimal_surplus[i]);
606 dio_get_sint16_raw(&din, &parameter->factor[i]);
608
609 dio_get_sint16_raw(&din, &parameter->happy_factor);
610 dio_get_uint8_raw(&din, &dummy); /* Dummy value; used to be factor_target. */
611 dio_get_bool8_raw(&din, &parameter->require_happy);
612 if (version > 2) {
613 dio_get_bool8_raw(&din, &parameter->max_growth);
614 }
615
616 return TRUE;
617}
618
619/************************************************************************/
622void cma_set_parameter(enum attr_city attr, int city_id,
623 const struct cm_parameter *parameter)
624{
625 char buffer[SAVED_PARAMETER_SIZE];
626 struct raw_data_out dout;
627
628 /* Changing this function is likely to break compatibility with old
629 * savegames that store these values. */
630
631 dio_output_init(&dout, buffer, sizeof(buffer));
632
634
637 dio_put_sint16_raw(&dout, parameter->factor[i]);
639
641 dio_put_uint8_raw(&dout, 0); /* Dummy value; used to be factor_target. */
643 dio_put_bool8_raw(&dout, parameter->max_growth);
644
646
647 attr_city_set(attr, city_id, SAVED_PARAMETER_SIZE, buffer);
648}
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:492
void attr_city_set(enum attr_city what, int city_id, size_t data_length, const void *const data)
Definition attribute.c:483
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:1133
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:1452
#define city_tile(_pcity_)
Definition city.h:564
static citizens city_size_get(const struct city *pcity)
Definition city.h:569
#define city_tile_iterate_skip_free_worked(_nmap, _radius_sq, _city_tile, _tile, _index, _x, _y)
Definition city.h:214
#define output_type_iterate(output)
Definition city.h:836
#define city_owner(_pcity_)
Definition city.h:563
#define city_tile_iterate_skip_free_worked_end
Definition city.h:222
#define city_map_iterate_end
Definition city.h:177
#define city_map_iterate(_radius_sq, _index, _x, _y)
Definition city.h:173
#define is_free_worked_index(city_tile_index)
Definition city.h:871
#define output_type_iterate_end
Definition city.h:842
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:1082
void cm_clear_cache(struct city *pcity)
Definition cm.c:322
void cm_init_parameter(struct cm_parameter *dest)
Definition cm.c:2180
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:2258
void cm_result_destroy(struct cm_result *result)
Definition cm.c:368
void cm_print_result(const struct cm_result *result)
Definition cm.c:2466
void cm_query_result(struct city *pcity, const struct cm_parameter *param, struct cm_result *result, bool negative_ok)
Definition cm.c:2120
int cm_result_citizens(const struct cm_result *result)
Definition cm.c:2249
void cm_print_city(const struct city *pcity)
Definition cm.c:2428
#define ALWAYS_APPLY_AT_SERVER
Definition cma_core.c:80
int refresh_forced
Definition cma_core.c:92
#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:141
#define CMA_ATTR_VERSION_MIN_SUPPORTED
Definition cma_core.c:85
static void report_stats(void)
Definition cma_core.c:338
#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
bool cma_is_city_under_agent(const struct city *pcity, struct cm_parameter *parameter)
Definition cma_core.c:551
static void city_changed(int city_id)
Definition cma_core.c:447
int apply_result_ignored
Definition cma_core.c:92
static void release_city(int city_id)
Definition cma_core.c:357
struct timer * wall_timer
Definition cma_core.c:91
void cma_put_city_under_agent(struct city *pcity, const struct cm_parameter *const parameter)
Definition cma_core.c:523
static void city_remove(int city_id)
Definition cma_core.c:460
static void new_turn(void)
Definition cma_core.c:468
static void handle_city(struct city *pcity)
Definition cma_core.c:371
int apply_result_applied
Definition cma_core.c:92
bool cma_get_parameter(enum attr_city attr, int city_id, struct cm_parameter *parameter)
Definition cma_core.c:574
static bool apply_result_on_server(struct city *pcity, const struct cm_result *result)
Definition cma_core.c:168
static bool fc_results_are_equal(const struct cm_result *result1, const struct cm_result *result2)
Definition cma_core.c:99
void cma_release_city(struct city *pcity)
Definition cma_core.c:541
#define CMA_ATTR_VERSION
Definition cma_core.c:84
void cma_set_parameter(enum attr_city attr, int city_id, const struct cm_parameter *parameter)
Definition cma_core.c:622
bool cma_apply_result(struct city *pcity, const struct cm_result *result)
Definition cma_core.c:509
static struct @128 stats
#define log_apply_result
Definition cma_core.c:73
void cma_init(void)
Definition cma_core.c:477
char * incite_cost
Definition comments.c:74
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
#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:191
#define log_test
Definition log.h:136
#define log_verbose(message,...)
Definition log.h:109
#define fc_assert(condition)
Definition log.h:176
#define fc_assert_ret_val(condition, val)
Definition log.h:194
#define fc_assert_action(condition, action)
Definition log.h:187
#define log_debug(message,...)
Definition log.h:115
#define log_error(message,...)
Definition log.h:103
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
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:320
int id
Definition city.h:326
citizens specialists[SP_MAX]
Definition city.h:336
struct tile * tile
Definition city.h:322
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
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