Freeciv-3.3
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
364 if (!pcall) {
365 break;
366 }
367
368 free(pcall);
369 }
370
371 for (i = 0; i < agents.entries_used; i++) {
372 struct my_agent *agent = &agents.entries[i];
373
374 timer_destroy(agent->stats.network_wall_timer);
375 }
377}
378
379/************************************************************************/
382void register_agent(const struct agent *agent)
383{
384 struct my_agent *priv_agent = &agents.entries[agents.entries_used];
385
386 fc_assert_ret(agents.entries_used < MAX_AGENTS);
388
389 memcpy(&priv_agent->agent, agent, sizeof(struct agent));
390
391 priv_agent->first_outstanding_request_id = 0;
392 priv_agent->last_outstanding_request_id = 0;
393
394 priv_agent->stats.network_wall_timer = timer_new(TIMER_USER, TIMER_ACTIVE,
395 "agent: network");
396 priv_agent->stats.wait_at_network = 0;
397 priv_agent->stats.wait_at_network_requests = 0;
398
399 agents.entries_used++;
400}
401
402/************************************************************************/
406{
407 log_meta_callback("agents_disconnect()");
409}
410
411/************************************************************************/
415{
416 log_meta_callback("agents_processing_started()");
417 freeze();
418}
419
420/************************************************************************/
424{
425 log_meta_callback("agents_processing_finished()");
426 thaw();
427}
428
429/************************************************************************/
433{
434 log_meta_callback("agents_freeze_hint()");
435 freeze();
436}
437
438/************************************************************************/
442{
443 log_meta_callback("agents_thaw_hint()");
444 thaw();
445}
446
447/************************************************************************/
451{
452 log_meta_callback("agents_game_joined()");
453}
454
455/************************************************************************/
459{
460 log_meta_callback("agents_game_start()");
462}
463
464/************************************************************************/
468{
469 log_meta_callback("agents_before_new_turn()");
470}
471
472/************************************************************************/
476{
477 log_meta_callback("agents_start_turn()");
478}
479
480/************************************************************************/
485{
486 int i;
487
488 for (i = 0; i < agents.entries_used; i++) {
489 struct my_agent *agent = &agents.entries[i];
490
492 continue;
493 }
494 if (agent->agent.turn_start_notify) {
495 enqueue_call(OCT_NEW_TURN, CB_LAST, agent);
496 }
497 }
498 /*
499 * call_handle_methods() isn't called here because the agents are
500 * frozen anyway.
501 */
502}
503
504/************************************************************************/
513{
514 int i;
515
516 log_debug("A: agents_unit_changed(unit=%d) type=%s pos=(%d,%d) owner=%s",
519
520 for (i = 0; i < agents.entries_used; i++) {
521 struct my_agent *agent = &agents.entries[i];
522
524 continue;
525 }
526 if (agent->agent.unit_callbacks[CB_CHANGE]) {
527 enqueue_call(OCT_UNIT, CB_CHANGE, agent, punit->id);
528 }
529 }
531}
532
533/************************************************************************/
538{
539 int i;
540
541 log_debug("A: agents_new_unit(unit=%d) type=%s pos=(%d,%d) owner=%s",
544
545 for (i = 0; i < agents.entries_used; i++) {
546 struct my_agent *agent = &agents.entries[i];
547
549 continue;
550 }
551 if (agent->agent.unit_callbacks[CB_NEW]) {
552 enqueue_call(OCT_UNIT, CB_NEW, agent, punit->id);
553 }
554 }
555
557}
558
559/************************************************************************/
564{
565 int i;
566
567 log_debug("A: agents_remove_unit(unit=%d) type=%s pos=(%d,%d) owner=%s",
570
571 for (i = 0; i < agents.entries_used; i++) {
572 struct my_agent *agent = &agents.entries[i];
573
575 continue;
576 }
577 if (agent->agent.unit_callbacks[CB_REMOVE]) {
578 enqueue_call(OCT_UNIT, CB_REMOVE, agent, punit->id);
579 }
580 }
581
583}
584
585/************************************************************************/
590{
591 int i;
592
593 log_debug("A: agents_city_changed(city %d=\"%s\") owner=%s",
596
597 for (i = 0; i < agents.entries_used; i++) {
598 struct my_agent *agent = &agents.entries[i];
599
601 continue;
602 }
603 if (agent->agent.city_callbacks[CB_CHANGE]) {
604 enqueue_call(OCT_CITY, CB_CHANGE, agent, pcity->id);
605 }
606 }
607
609}
610
611/************************************************************************/
616{
617 int i;
618
619 log_debug("A: agents_city_new(city %d=\"%s\") pos=(%d,%d) owner=%s",
622
623 for (i = 0; i < agents.entries_used; i++) {
624 struct my_agent *agent = &agents.entries[i];
625
627 continue;
628 }
629 if (agent->agent.city_callbacks[CB_NEW]) {
630 enqueue_call(OCT_CITY, CB_NEW, agent, pcity->id);
631 }
632 }
633
635}
636
637/************************************************************************/
642{
643 int i;
644
645 log_debug("A: agents_city_remove(city %d=\"%s\") pos=(%d,%d) owner=%s",
648
649 for (i = 0; i < agents.entries_used; i++) {
650 struct my_agent *agent = &agents.entries[i];
651
653 continue;
654 }
655 if (agent->agent.city_callbacks[CB_REMOVE]) {
656 enqueue_call(OCT_CITY, CB_REMOVE, agent, pcity->id);
657 }
658 }
659
661}
662
663/************************************************************************/
668void agents_tile_remove(struct tile *ptile)
669{
670 int i;
671
672 log_debug("A: agents_tile_remove(tile=(%d, %d))", TILE_XY(ptile));
673
674 for (i = 0; i < agents.entries_used; i++) {
675 struct my_agent *agent = &agents.entries[i];
676
678 continue;
679 }
680 if (agent->agent.tile_callbacks[CB_REMOVE]) {
681 enqueue_call(OCT_TILE, CB_REMOVE, agent, ptile);
682 }
683 }
684
686}
687
688/************************************************************************/
692void agents_tile_changed(struct tile *ptile)
693{
694 int i;
695
696 log_debug("A: agents_tile_changed(tile=(%d, %d))", TILE_XY(ptile));
697
698 for (i = 0; i < agents.entries_used; i++) {
699 struct my_agent *agent = &agents.entries[i];
700
702 continue;
703 }
704 if (agent->agent.tile_callbacks[CB_CHANGE]) {
705 enqueue_call(OCT_TILE, CB_CHANGE, agent, ptile);
706 }
707 }
708
710}
711
712/************************************************************************/
716void agents_tile_new(struct tile *ptile)
717{
718 int i;
719
720 log_debug("A: agents_tile_new(tile=(%d, %d))", TILE_XY(ptile));
721
722 for (i = 0; i < agents.entries_used; i++) {
723 struct my_agent *agent = &agents.entries[i];
724
726 continue;
727 }
728 if (agent->agent.tile_callbacks[CB_NEW]) {
729 enqueue_call(OCT_TILE, CB_NEW, agent, ptile);
730 }
731 }
732
734}
735
736/************************************************************************/
741 int last_request_id)
742{
743 struct my_agent *agent = agent_by_name(agent_name);
744
745 log_request_ids("A:%s: wait_for_request(ids=[%d..%d])",
747
750 fc_assert_ret(agent->first_outstanding_request_id == 0);
751 agent->first_outstanding_request_id = first_request_id;
752 agent->last_outstanding_request_id = last_request_id;
753
754 timer_start(agent->stats.network_wall_timer);
756 timer_stop(agent->stats.network_wall_timer);
757
758 agent->stats.wait_at_network++;
759 agent->stats.wait_at_network_requests +=
761
762 log_request_ids("A:%s: wait_for_request: ids=[%d..%d]; got it",
764
765 agent->first_outstanding_request_id = 0;
766
767 log_debug("A:%s: waited %fs in total for network; "
768 "requests=%d; waited %d times",
769 agent->agent.name,
770 timer_read_seconds(agent->stats.network_wall_timer),
771 agent->stats.wait_at_network_requests,
772 agent->stats.wait_at_network);
773}
774
775/************************************************************************/
787
788/************************************************************************/
800
801/************************************************************************/
804bool agents_busy(void)
805{
806 int i;
807
808 if (!initialized) {
809 return FALSE;
810 }
811
812 if (call_list_size(agents.calls) > 0 || frozen_level > 0
814 return TRUE;
815 }
816
817 for (i = 0; i < agents.entries_used; i++) {
818 struct my_agent *agent = &agents.entries[i];
819
820 if (agent->first_outstanding_request_id != 0) {
821 return TRUE;
822 }
823 }
824 return FALSE;
825}
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
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:512
void agents_city_remove(struct city *pcity)
Definition agents.c:641
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:441
void agents_disconnect(void)
Definition agents.c:405
void agents_game_start(void)
Definition agents.c:458
void wait_for_requests(const char *agent_name, int first_request_id, int last_request_id)
Definition agents.c:740
void agents_tile_remove(struct tile *ptile)
Definition agents.c:668
void agents_city_new(struct city *pcity)
Definition agents.c:615
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:475
void agents_tile_changed(struct tile *ptile)
Definition agents.c:692
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
void agents_unit_new(struct unit *punit)
Definition agents.c:537
static struct @130 agents
static struct call * remove_and_return_a_call(void)
Definition agents.c:196
struct @130::my_agent entries[MAX_AGENTS]
bool agents_busy(void)
Definition agents.c:804
void agents_unit_remove(struct unit *punit)
Definition agents.c:563
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:414
void agents_tile_new(struct tile *ptile)
Definition agents.c:716
void agents_processing_finished(void)
Definition agents.c:423
void agents_new_turn(void)
Definition agents.c:484
#define log_request_ids(...)
Definition agents.c:43
void agents_city_changed(struct city *pcity)
Definition agents.c:589
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:791
void agents_game_joined(void)
Definition agents.c:450
struct @130::my_agent::@131 stats
#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:382
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:778
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:432
void agents_before_new_turn(void)
Definition agents.c:467
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:76
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 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
struct world wld
Definition game.c:62
GType type
Definition repodlgs.c:1313
#define fc_assert_ret(condition)
Definition log.h:192
#define fc_assert(condition)
Definition log.h:177
#define log_debug(message,...)
Definition log.h:116
#define log_error(message,...)
Definition log.h:104
struct tile * index_to_tile(const struct civ_map *imap, int mindex)
Definition map.c:471
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:317
struct connection conn
Definition client_main.h:96
int request_id_of_currently_handled_packet
Definition connection.h:193
struct connection::@61::@66 client
Definition tile.h:50
Definition timing.c:81
Definition unit.h:140
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_index(_pt_)
Definition tile.h:89
#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:263
void timer_stop(struct timer *t)
Definition timing.c:305
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:379
@ TIMER_ACTIVE
Definition timing.h:46
@ TIMER_USER
Definition timing.h:42
#define unit_tile(_pu)
Definition unit.h:404
#define unit_owner(_pu)
Definition unit.h:403
const char * unit_rule_name(const struct unit *punit)
Definition unittype.c:1593