Freeciv-3.2
Loading...
Searching...
No Matches
agents.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 <stdarg.h>
19#include <string.h>
20
21/* utility */
22#include "capability.h"
23#include "log.h"
24#include "mem.h"
25#include "timing.h"
26
27/* common */
28#include "nation.h"
29
30/* client */
31#include "client_main.h"
32
33/* include */
34#include "mapctrl_g.h"
35
36/* agents */
37#include "cma_core.h"
38#include "cma_fec.h"
39#include "sha.h"
40
41#include "agents.h"
42
43#define log_request_ids(...) /* log_test(__VA_ARGS__) */
44#define log_todo_lists(...) /* log_test(__VA_ARGS__) */
45#define log_meta_callback(...) log_debug(__VA_ARGS__)
46#define log_debug_freeze(...) /* log_test(__VA_ARGS__) */
47
48#define MAX_AGENTS 10
49
50struct my_agent;
51
52struct call {
53 struct my_agent *agent;
56 int arg;
57};
58
59#define SPECLIST_TAG call
60#define SPECLIST_TYPE struct call
61#include "speclist.h"
62
63#define call_list_iterate(calllist, pcall) \
64 TYPED_LIST_ITERATE(struct call, calllist, pcall)
65#define call_list_iterate_end LIST_ITERATE_END
66
67#define call_list_both_iterate(calllist, plink, pcall) \
68 TYPED_LIST_BOTH_ITERATE(struct call_list_link, struct call, \
69 calllist, plink, pcall)
70#define call_list_both_iterate_end LIST_BOTH_ITERATE_END
71
72/*
73 * Main data structure. Contains all registered agents and all
74 * outstanding calls.
75 */
76static struct {
78 struct my_agent {
79 struct agent agent;
81 struct {
88
89static bool initialized = FALSE;
90static int frozen_level;
92
93/************************************************************************/
96static bool calls_are_equal(const struct call *pcall1,
97 const struct call *pcall2)
98{
99 if (pcall1->agent != pcall2->agent) {
100 return FALSE;
101 }
102
103 if (pcall1->type != pcall2->type && pcall1->cb_type != pcall2->cb_type) {
104 return FALSE;
105 }
106
107 switch (pcall1->type) {
108 case OCT_UNIT:
109 case OCT_CITY:
110 case OCT_TILE:
111 return (pcall1->arg == pcall2->arg);
112 case OCT_NEW_TURN:
113 return TRUE;
114 }
115
116 log_error("Unsupported call type %d.", pcall1->type);
117 return FALSE;
118}
119
120/************************************************************************/
125static void enqueue_call(enum oct type,
126 enum callback_type cb_type,
127 struct my_agent *agent, ...)
128{
129 va_list ap;
130 struct call *pcall2;
131 int arg = 0;
132 const struct tile *ptile;
133 bool added = FALSE;
134
135 va_start(ap, agent);
136
137 if (client_is_observer()) {
138 return;
139 }
140
141 switch (type) {
142 case OCT_UNIT:
143 case OCT_CITY:
144 arg = va_arg(ap, int);
145 break;
146 case OCT_TILE:
147 ptile = va_arg(ap, const struct tile *);
148 arg = tile_index(ptile);
149 break;
150 case OCT_NEW_TURN:
151 /* nothing */
152 break;
153 }
154 va_end(ap);
155
156 pcall2 = fc_malloc(sizeof(struct call));
157
158 pcall2->agent = agent;
159 pcall2->type = type;
160 pcall2->cb_type = cb_type;
161 pcall2->arg = arg;
162
163 /* Ensure list is sorted so that calls to agents with lower levels
164 * come first, since that's how we'll want to pop them */
165 call_list_both_iterate(agents.calls, plink, pcall) {
167 /* Already got one like this, discard duplicate. */
168 free(pcall2);
169 return;
170 }
171 if (pcall->agent->agent.level - pcall2->agent->agent.level > 0) {
172 /* Found a level greater than ours. Can assume that calls_are_equal()
173 * will never be true from here on, since list is sorted by level and
174 * unequal levels => unequal agents => !calls_are_equal().
175 * Insert into list here. */
177 added = TRUE;
178 break;
179 }
181
182 if (!added) {
184 }
185
186 log_todo_lists("A: adding call");
187
188 /* agents_busy() may have changed */
190}
191
192/************************************************************************/
196static struct call *remove_and_return_a_call(void)
197{
198 struct call *result;
199
200 if (call_list_size(agents.calls) == 0) {
201 return NULL;
202 }
203
204 result = call_list_front(agents.calls);
206
207 log_todo_lists("A: removed call");
208 return result;
209}
210
211/************************************************************************/
214static void execute_call(const struct call *call)
215{
216 switch (call->type) {
217 case OCT_NEW_TURN:
218 call->agent->agent.turn_start_notify();
219 break;
220 case OCT_UNIT:
221 call->agent->agent.unit_callbacks[call->cb_type] (call->arg);
222 break;
223 case OCT_CITY:
224 call->agent->agent.city_callbacks[call->cb_type] (call->arg);
225 break;
226 case OCT_TILE:
227 call->agent->agent.tile_callbacks[call->cb_type]
228 (index_to_tile(&(wld.map), call->arg));
229 break;
230 }
231}
232
233/************************************************************************/
238static void call_handle_methods(void)
239{
240 if (currently_running) {
241 return;
242 }
243 if (frozen_level > 0) {
244 return;
245 }
247
248 /*
249 * The following should ensure that the methods of agents which have
250 * a lower level are called first.
251 */
252 for (;;) {
253 struct call *pcall;
254
256 if (!pcall) {
257 break;
258 }
259
261 free(pcall);
262 }
263
265
267}
268
269/************************************************************************/
272static void freeze(void)
273{
274 if (!initialized) {
275 frozen_level = 0;
277 }
278 log_debug_freeze("A: freeze() current level=%d", frozen_level);
279 frozen_level++;
280}
281
282/************************************************************************/
286static void thaw(void)
287{
288 log_debug_freeze("A: thaw() current level=%d", frozen_level);
289 frozen_level--;
291 if (0 == frozen_level && C_S_RUNNING == client_state()) {
293 }
294}
295
296/************************************************************************/
299static struct my_agent *agent_by_name(const char *agent_name)
300{
301 int i;
302
303 for (i = 0; i < agents.entries_used; i++) {
304 if (strcmp(agent_name, agents.entries[i].agent.name) == 0)
305 return &agents.entries[i];
306 }
307
308 return NULL;
309}
310
311/************************************************************************/
315static bool is_outstanding_request(struct my_agent *agent)
316{
317 if (agent->first_outstanding_request_id != 0
319 && agent->first_outstanding_request_id <=
321 && agent->last_outstanding_request_id >=
323 log_debug("A:%s: ignoring packet; outstanding [%d..%d] got=%d",
324 agent->agent.name, agent->first_outstanding_request_id,
325 agent->last_outstanding_request_id,
327 return TRUE;
328 }
329 return FALSE;
330}
331
332/************************************************************************/
335void agents_init(void)
336{
337 agents.entries_used = 0;
338 agents.calls = call_list_new();
339
340 /* Add init calls of agents here */
341 cma_init();
342 cmafec_init();
343 /*simple_historian_init();*/
344}
345
346/************************************************************************/
349void agents_free(void)
350{
351 int i;
352
353 /* FIXME: doing this will wipe out any presets on disconnect.
354 * a proper solution should be to split up the client_free functions
355 * for a simple disconnect and a client quit. for right now, we just
356 * let the OS free the memory on exit instead of doing it ourselves. */
357 /* cmafec_free(); */
358
359 /*simple_historian_done();*/
360
361 for (;;) {
363 if (!pcall) {
364 break;
365 }
366
367 free(pcall);
368 }
369
370 for (i = 0; i < agents.entries_used; i++) {
371 struct my_agent *agent = &agents.entries[i];
372
373 timer_destroy(agent->stats.network_wall_timer);
374 }
376}
377
378/************************************************************************/
381void register_agent(const struct agent *agent)
382{
383 struct my_agent *priv_agent = &agents.entries[agents.entries_used];
384
385 fc_assert_ret(agents.entries_used < MAX_AGENTS);
387
388 memcpy(&priv_agent->agent, agent, sizeof(struct agent));
389
390 priv_agent->first_outstanding_request_id = 0;
391 priv_agent->last_outstanding_request_id = 0;
392
393 priv_agent->stats.network_wall_timer = timer_new(TIMER_USER, TIMER_ACTIVE,
394 "agent: network");
395 priv_agent->stats.wait_at_network = 0;
396 priv_agent->stats.wait_at_network_requests = 0;
397
398 agents.entries_used++;
399}
400
401/************************************************************************/
405{
406 log_meta_callback("agents_disconnect()");
408}
409
410/************************************************************************/
414{
415 log_meta_callback("agents_processing_started()");
416 freeze();
417}
418
419/************************************************************************/
423{
424 log_meta_callback("agents_processing_finished()");
425 thaw();
426}
427
428/************************************************************************/
432{
433 log_meta_callback("agents_freeze_hint()");
434 freeze();
435}
436
437/************************************************************************/
441{
442 log_meta_callback("agents_thaw_hint()");
443 thaw();
444}
445
446/************************************************************************/
450{
451 log_meta_callback("agents_game_joined()");
452}
453
454/************************************************************************/
458{
459 log_meta_callback("agents_game_start()");
461}
462
463/************************************************************************/
467{
468 log_meta_callback("agents_before_new_turn()");
469}
470
471/************************************************************************/
475{
476 log_meta_callback("agents_start_turn()");
477}
478
479/************************************************************************/
484{
485 int i;
486
487 for (i = 0; i < agents.entries_used; i++) {
488 struct my_agent *agent = &agents.entries[i];
489
491 continue;
492 }
493 if (agent->agent.turn_start_notify) {
494 enqueue_call(OCT_NEW_TURN, CB_LAST, agent);
495 }
496 }
497 /*
498 * call_handle_methods() isn't called here because the agents are
499 * frozen anyway.
500 */
501}
502
503/************************************************************************/
512{
513 int i;
514
515 log_debug("A: agents_unit_changed(unit=%d) type=%s pos=(%d,%d) owner=%s",
518
519 for (i = 0; i < agents.entries_used; i++) {
520 struct my_agent *agent = &agents.entries[i];
521
523 continue;
524 }
525 if (agent->agent.unit_callbacks[CB_CHANGE]) {
526 enqueue_call(OCT_UNIT, CB_CHANGE, agent, punit->id);
527 }
528 }
530}
531
532/************************************************************************/
537{
538 int i;
539
540 log_debug("A: agents_new_unit(unit=%d) type=%s pos=(%d,%d) owner=%s",
543
544 for (i = 0; i < agents.entries_used; i++) {
545 struct my_agent *agent = &agents.entries[i];
546
548 continue;
549 }
550 if (agent->agent.unit_callbacks[CB_NEW]) {
551 enqueue_call(OCT_UNIT, CB_NEW, agent, punit->id);
552 }
553 }
554
556}
557
558/************************************************************************/
563{
564 int i;
565
566 log_debug("A: agents_remove_unit(unit=%d) type=%s pos=(%d,%d) owner=%s",
569
570 for (i = 0; i < agents.entries_used; i++) {
571 struct my_agent *agent = &agents.entries[i];
572
574 continue;
575 }
576 if (agent->agent.unit_callbacks[CB_REMOVE]) {
577 enqueue_call(OCT_UNIT, CB_REMOVE, agent, punit->id);
578 }
579 }
580
582}
583
584/************************************************************************/
588void agents_city_changed(struct city *pcity)
589{
590 int i;
591
592 log_debug("A: agents_city_changed(city %d=\"%s\") owner=%s",
593 pcity->id, city_name_get(pcity),
595
596 for (i = 0; i < agents.entries_used; i++) {
597 struct my_agent *agent = &agents.entries[i];
598
600 continue;
601 }
602 if (agent->agent.city_callbacks[CB_CHANGE]) {
603 enqueue_call(OCT_CITY, CB_CHANGE, agent, pcity->id);
604 }
605 }
606
608}
609
610/************************************************************************/
614void agents_city_new(struct city *pcity)
615{
616 int i;
617
618 log_debug("A: agents_city_new(city %d=\"%s\") pos=(%d,%d) owner=%s",
619 pcity->id, city_name_get(pcity), TILE_XY(pcity->tile),
621
622 for (i = 0; i < agents.entries_used; i++) {
623 struct my_agent *agent = &agents.entries[i];
624
626 continue;
627 }
628 if (agent->agent.city_callbacks[CB_NEW]) {
629 enqueue_call(OCT_CITY, CB_NEW, agent, pcity->id);
630 }
631 }
632
634}
635
636/************************************************************************/
640void agents_city_remove(struct city *pcity)
641{
642 int i;
643
644 log_debug("A: agents_city_remove(city %d=\"%s\") pos=(%d,%d) owner=%s",
645 pcity->id, city_name_get(pcity), TILE_XY(pcity->tile),
647
648 for (i = 0; i < agents.entries_used; i++) {
649 struct my_agent *agent = &agents.entries[i];
650
652 continue;
653 }
654 if (agent->agent.city_callbacks[CB_REMOVE]) {
655 enqueue_call(OCT_CITY, CB_REMOVE, agent, pcity->id);
656 }
657 }
658
660}
661
662/************************************************************************/
667void agents_tile_remove(struct tile *ptile)
668{
669 int i;
670
671 log_debug("A: agents_tile_remove(tile=(%d, %d))", TILE_XY(ptile));
672
673 for (i = 0; i < agents.entries_used; i++) {
674 struct my_agent *agent = &agents.entries[i];
675
677 continue;
678 }
679 if (agent->agent.tile_callbacks[CB_REMOVE]) {
680 enqueue_call(OCT_TILE, CB_REMOVE, agent, ptile);
681 }
682 }
683
685}
686
687/************************************************************************/
691void agents_tile_changed(struct tile *ptile)
692{
693 int i;
694
695 log_debug("A: agents_tile_changed(tile=(%d, %d))", TILE_XY(ptile));
696
697 for (i = 0; i < agents.entries_used; i++) {
698 struct my_agent *agent = &agents.entries[i];
699
701 continue;
702 }
703 if (agent->agent.tile_callbacks[CB_CHANGE]) {
704 enqueue_call(OCT_TILE, CB_CHANGE, agent, ptile);
705 }
706 }
707
709}
710
711/************************************************************************/
715void agents_tile_new(struct tile *ptile)
716{
717 int i;
718
719 log_debug("A: agents_tile_new(tile=(%d, %d))", TILE_XY(ptile));
720
721 for (i = 0; i < agents.entries_used; i++) {
722 struct my_agent *agent = &agents.entries[i];
723
725 continue;
726 }
727 if (agent->agent.tile_callbacks[CB_NEW]) {
728 enqueue_call(OCT_TILE, CB_NEW, agent, ptile);
729 }
730 }
731
733}
734
735/************************************************************************/
740 int last_request_id)
741{
742 struct my_agent *agent = agent_by_name(agent_name);
743
744 log_request_ids("A:%s: wait_for_request(ids=[%d..%d])",
746
749 fc_assert_ret(agent->first_outstanding_request_id == 0);
750 agent->first_outstanding_request_id = first_request_id;
751 agent->last_outstanding_request_id = last_request_id;
752
753 timer_start(agent->stats.network_wall_timer);
755 timer_stop(agent->stats.network_wall_timer);
756
757 agent->stats.wait_at_network++;
758 agent->stats.wait_at_network_requests +=
760
761 log_request_ids("A:%s: wait_for_request: ids=[%d..%d]; got it",
763
764 agent->first_outstanding_request_id = 0;
765
766 log_debug("A:%s: waited %fs in total for network; "
767 "requests=%d; waited %d times",
768 agent->agent.name,
769 timer_read_seconds(agent->stats.network_wall_timer),
770 agent->stats.wait_at_network_requests,
771 agent->stats.wait_at_network);
772}
773
774/************************************************************************/
786
787/************************************************************************/
791 struct city *pcity)
792{
793 struct my_agent *agent = agent_by_name(name_of_calling_agent);
794
796 enqueue_call(OCT_CITY, CB_CHANGE, agent, pcity->id);
798}
799
800/************************************************************************/
803bool agents_busy(void)
804{
805 int i;
806
807 if (!initialized) {
808 return FALSE;
809 }
810
811 if (call_list_size(agents.calls) > 0 || frozen_level > 0
813 return TRUE;
814 }
815
816 for (i = 0; i < agents.entries_used; i++) {
817 struct my_agent *agent = &agents.entries[i];
818
819 if (agent->first_outstanding_request_id != 0) {
820 return TRUE;
821 }
822 }
823 return FALSE;
824}
struct agent agent
Definition agents.c:79
struct call_list * calls
Definition agents.c:86
#define log_todo_lists(...)
Definition agents.c:44
static struct my_agent * agent_by_name(const char *agent_name)
Definition agents.c:299
struct @126::my_agent::@127 stats
static void enqueue_call(enum oct type, enum callback_type cb_type, struct my_agent *agent,...)
Definition agents.c:125
static bool calls_are_equal(const struct call *pcall1, const struct call *pcall2)
Definition agents.c:96
void agents_unit_changed(struct unit *punit)
Definition agents.c:511
void agents_city_remove(struct city *pcity)
Definition agents.c:640
static int frozen_level
Definition agents.c:90
int entries_used
Definition agents.c:77
void agents_free(void)
Definition agents.c:349
void agents_thaw_hint(void)
Definition agents.c:440
void agents_disconnect(void)
Definition agents.c:404
void agents_game_start(void)
Definition agents.c:457
void wait_for_requests(const char *agent_name, int first_request_id, int last_request_id)
Definition agents.c:739
void agents_tile_remove(struct tile *ptile)
Definition agents.c:667
void agents_city_new(struct city *pcity)
Definition agents.c:614
struct timer * network_wall_timer
Definition agents.c:82
int wait_at_network_requests
Definition agents.c:83
#define call_list_both_iterate_end
Definition agents.c:70
int first_outstanding_request_id
Definition agents.c:80
void agents_start_turn(void)
Definition agents.c:474
void agents_tile_changed(struct tile *ptile)
Definition agents.c:691
int wait_at_network
Definition agents.c:83
static void freeze(void)
Definition agents.c:272
static void call_handle_methods(void)
Definition agents.c:238
struct @126::my_agent entries[MAX_AGENTS]
void agents_unit_new(struct unit *punit)
Definition agents.c:536
static struct call * remove_and_return_a_call(void)
Definition agents.c:196
bool agents_busy(void)
Definition agents.c:803
void agents_unit_remove(struct unit *punit)
Definition agents.c:562
static bool currently_running
Definition agents.c:91
static bool is_outstanding_request(struct my_agent *agent)
Definition agents.c:315
void agents_processing_started(void)
Definition agents.c:413
void agents_tile_new(struct tile *ptile)
Definition agents.c:715
void agents_processing_finished(void)
Definition agents.c:422
void agents_new_turn(void)
Definition agents.c:483
#define log_request_ids(...)
Definition agents.c:43
void agents_city_changed(struct city *pcity)
Definition agents.c:588
static struct @126 agents
int last_outstanding_request_id
Definition agents.c:80
void cause_a_city_changed_for_agent(const char *name_of_calling_agent, struct city *pcity)
Definition agents.c:790
void agents_game_joined(void)
Definition agents.c:449
#define MAX_AGENTS
Definition agents.c:48
static void thaw(void)
Definition agents.c:286
void register_agent(const struct agent *agent)
Definition agents.c:381
void agents_init(void)
Definition agents.c:335
void cause_a_unit_changed_for_agent(const char *name_of_calling_agent, struct unit *punit)
Definition agents.c:777
static void execute_call(const struct call *call)
Definition agents.c:214
#define call_list_both_iterate(calllist, plink, pcall)
Definition agents.c:67
static bool initialized
Definition agents.c:89
#define log_debug_freeze(...)
Definition agents.c:46
#define log_meta_callback(...)
Definition agents.c:45
void agents_freeze_hint(void)
Definition agents.c:431
void agents_before_new_turn(void)
Definition agents.c:466
callback_type
Definition agents.h:36
@ CB_LAST
Definition agents.h:37
@ CB_NEW
Definition agents.h:37
@ CB_REMOVE
Definition agents.h:37
@ CB_CHANGE
Definition agents.h:37
const char * city_name_get(const struct city *pcity)
Definition city.c:1137
bool client_is_observer(void)
struct civclient client
enum client_states client_state(void)
void wait_till_request_got_processed(int request_id)
@ C_S_RUNNING
Definition client_main.h:47
void cma_init(void)
Definition cma_core.c:478
void cmafec_init(void)
Definition cma_fec.c:76
char * incite_cost
Definition comments.c:75
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 * punit
Definition dialogs_g.h:74
struct world wld
Definition game.c:63
GType type
Definition repodlgs.c:1313
#define fc_assert_ret(condition)
Definition log.h:191
#define fc_assert(condition)
Definition log.h:176
#define log_debug(message,...)
Definition log.h:115
#define log_error(message,...)
Definition log.h:103
struct tile * index_to_tile(const struct civ_map *imap, int mindex)
Definition map.c:456
void update_turn_done_button_state(void)
#define fc_malloc(sz)
Definition mem.h:34
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
const char * player_name(const struct player *pplayer)
Definition player.c:895
Definition agents.h:40
int level
Definition agents.h:42
void(* unit_callbacks[CB_LAST])(int)
Definition agents.h:46
void(* tile_callbacks[CB_LAST])(struct tile *ptile)
Definition agents.h:47
char name[MAX_AGENT_NAME_LEN]
Definition agents.h:41
void(* city_callbacks[CB_LAST])(int)
Definition agents.h:45
void(* turn_start_notify)(void)
Definition agents.h:44
Definition agents.c:52
enum callback_type cb_type
Definition agents.c:55
struct my_agent * agent
Definition agents.c:53
oct
Definition agents.c:54
@ OCT_CITY
Definition agents.c:54
@ OCT_TILE
Definition agents.c:54
@ OCT_NEW_TURN
Definition agents.c:54
@ OCT_UNIT
Definition agents.c:54
enum call::oct type
int arg
Definition agents.c:56
Definition city.h:320
int id
Definition city.h:326
struct tile * tile
Definition city.h:322
struct connection conn
Definition client_main.h:96
int request_id_of_currently_handled_packet
Definition connection.h:193
struct connection::@58::@63 client
Definition tile.h:50
Definition timing.c:81
Definition unit.h:138
int id
Definition unit.h:145
struct civ_map map
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
#define tile_index(_pt_)
Definition tile.h:88
#define TILE_XY(ptile)
Definition tile.h:43
void timer_destroy(struct timer *t)
Definition timing.c:208
void timer_start(struct timer *t)
Definition timing.c:264
void timer_stop(struct timer *t)
Definition timing.c:308
struct timer * timer_new(enum timer_timetype type, enum timer_use use, const char *name)
Definition timing.c:160
double timer_read_seconds(struct timer *t)
Definition timing.c:384
@ TIMER_ACTIVE
Definition timing.h:46
@ TIMER_USER
Definition timing.h:42
#define unit_tile(_pu)
Definition unit.h:397
#define unit_owner(_pu)
Definition unit.h:396
const char * unit_rule_name(const struct unit *punit)
Definition unittype.c:1587