Freeciv21
Develop your civilization from humble roots to a global empire
global_worklist.cpp
Go to the documentation of this file.
1 /*__ ___ ***************************************
2 / \ / \ Copyright (c) 1996-2020 Freeciv21 and Freeciv
3 \_ \ / __/ contributors. This file is part of Freeciv21.
4  _\ \ / /__ Freeciv21 is free software: you can redistribute it
5  \___ \____/ __/ and/or modify it under the terms of the GNU General
6  \_ _/ Public License as published by the Free Software
7  | @ @ \_ Foundation, either version 3 of the License,
8  | or (at your option) any later version.
9  _/ /\ You should have received a copy of the GNU
10  /o) (o/\ \_ General Public License along with Freeciv21.
11  \_____/ / If not, see https://www.gnu.org/licenses/.
12  \____/ ********************************************************/
13 #include <cstdarg>
14 
15 // utility
16 #include "fcintl.h"
17 #include "log.h"
18 #include "registry.h"
19 #include "registry_ini.h"
20 #include "shared.h"
21 #include "support.h"
22 
23 // common
24 #include "fc_types.h"
25 #include "requirements.h"
26 #include "worklist.h"
27 
28 // client
29 #include "client_main.h"
30 
31 #include "global_worklist.h"
32 
34  /* Means we have a list of kind of universal and their name, but we
35  * don't know the id they could have on the server's ruleset. In this
36  * case, we use the unbuilt part and not the worklist one. */
38 
39  // Means this worklist is plainly usable at running time.
41 };
42 
43 struct uni_name {
44  char *kind;
45  char *name;
46 };
47 
48 // The global worklist structure.
50  int id;
53  union {
54  struct {
55  int length;
58  struct worklist worklist;
59  };
60 };
61 
62 static bool global_worklist_load(struct section_file *file, const char *path,
63  ...)
64  fc__attribute((__format__(__printf__, 2, 3)));
65 static void global_worklist_save(const struct global_worklist *pgwl,
66  struct section_file *file, int fill_until,
67  const char *path, ...)
68  fc__attribute((__format__(__printf__, 4, 5)));
69 
74 {
75  if (!client.worklists) {
76  client.worklists = global_worklist_list_new();
77  }
78 }
79 
84 {
85  if (client.worklists) {
88  global_worklist_list_destroy(client.worklists);
89  client.worklists = nullptr;
90  }
91 }
92 
97 {
99  {
100  if (pgwl->status == STATUS_UNBUILT) {
101  struct worklist worklist;
102  struct uni_name *puni_name;
103  int i;
104 
105  // Build a worklist.
107  for (i = 0; i < pgwl->unbuilt.length; i++) {
108  struct universal source;
109 
110  puni_name = pgwl->unbuilt.entries + i;
111  source = universal_by_rule_name(puni_name->kind, puni_name->name);
112  if (source.kind == universals_n_invalid()) {
113  /* This worklist is not valid on this ruleset.
114  * N.B.: Don't remove it to resave it in client rc file. */
115  break;
116  } else {
117  worklist_append(&worklist, &source);
118  }
119  }
120 
121  if (worklist_length(&worklist) != pgwl->unbuilt.length) {
122  /* Somewhat in this worklist is not supported by the current
123  * ruleset. Don't try to build it, but keep it for later save. */
124  continue;
125  }
126 
127  // Now the worklist is built, change status.
128  for (i = 0; i < pgwl->unbuilt.length; i++) {
129  puni_name = pgwl->unbuilt.entries + i;
130  delete[] puni_name->kind;
131  delete[] puni_name->name;
132  }
133  pgwl->status = STATUS_WORKLIST;
134  worklist_copy(&pgwl->worklist, &worklist);
135  }
136  }
138 }
139 
144 {
146  {
147  if (pgwl->status == STATUS_WORKLIST) {
148  struct worklist worklist;
149  struct uni_name *puni_name;
150  int i;
151 
152  // Copy before over-write.
153  worklist_copy(&worklist, &pgwl->worklist);
154  pgwl->status = STATUS_UNBUILT;
155 
156  pgwl->unbuilt.length = worklist_length(&worklist);
157  for (i = 0; i < worklist_length(&worklist); i++) {
158  puni_name = pgwl->unbuilt.entries + i;
159  puni_name->kind =
161  puni_name->name =
163  }
164  }
165  }
167 }
168 
172 static struct global_worklist *
174 {
175  static int last_id = 0;
176  struct global_worklist *pgwl = new global_worklist[1]();
177 
178  pgwl->id = ++last_id;
179  pgwl->status = type;
180 
181  // Specific initializer.
182  switch (pgwl->status) {
183  case STATUS_UNBUILT:
184  // All members set to 0 by fc_calloc.
185  break;
186  case STATUS_WORKLIST:
187  worklist_init(&pgwl->worklist);
188  break;
189  }
190 
191  global_worklist_list_append(client.worklists, pgwl);
192 
193  return pgwl;
194 }
195 
200 {
201  fc_assert_ret(nullptr != pgwl);
202 
203  global_worklist_list_remove(client.worklists, pgwl);
204 
205  // Specific descturctor.
206  switch (pgwl->status) {
207  case STATUS_UNBUILT: {
208  struct uni_name *puni_name;
209  int i;
210 
211  for (i = 0; i < pgwl->unbuilt.length; i++) {
212  puni_name = pgwl->unbuilt.entries + i;
213  puni_name->kind = pgwl->unbuilt.entries[i].kind;
214  puni_name->name = pgwl->unbuilt.entries[i].name;
215  delete[] puni_name->kind;
216  delete[] puni_name->name;
217  }
218  } break;
219  case STATUS_WORKLIST:
220  break;
221  }
222 
223  delete[] pgwl;
224 }
225 
230 {
232 
234  return pgwl;
235 }
236 
241 {
242  return pgwl && pgwl->status == STATUS_WORKLIST;
243 }
244 
249  const struct worklist *pwl)
250 {
251  if (pgwl && pgwl->status == STATUS_WORKLIST && pwl) {
252  worklist_copy(&pgwl->worklist, pwl);
253  return true;
254  }
255  return false;
256 }
257 
261 const struct worklist *
263 {
264  if (pgwl && pgwl->status == STATUS_WORKLIST) {
265  return &pgwl->worklist;
266  } else {
267  return nullptr;
268  }
269 }
270 
274 int global_worklist_id(const struct global_worklist *pgwl)
275 {
276  fc_assert_ret_val(nullptr != pgwl, 0);
277  return pgwl->id;
278 }
279 
285 {
287  {
288  if (pgwl->id == id) {
289  return pgwl;
290  }
291  }
293 
294  return nullptr;
295 }
296 
300 void global_worklist_set_name(struct global_worklist *pgwl, const char *name)
301 {
302  if (name) {
303  sz_strlcpy(pgwl->name, name);
304  }
305 }
306 
310 const char *global_worklist_name(const struct global_worklist *pgwl)
311 {
312  fc_assert_ret_val(nullptr != pgwl, nullptr);
313  return pgwl->name;
314 }
315 
320 static bool global_worklist_load(struct section_file *file, const char *path,
321  ...)
322 {
323  struct global_worklist *pgwl;
324  const char *kind;
325  const char *name;
326  char path_str[1024];
327  va_list ap;
328  int i, length;
329 
330  /* The first part of the registry path is taken from the varargs to the
331  * function. */
332  va_start(ap, path);
333  fc_vsnprintf(path_str, sizeof(path_str), path, ap);
334  va_end(ap);
335 
336  length = secfile_lookup_int_default(file, -1, "%s.wl_length", path_str);
337  if (length == -1) {
338  // Not set.
339  return false;
340  }
344  pgwl, secfile_lookup_str_default(file, _("(noname)"), "%s.wl_name",
345  path_str));
346 
347  for (i = 0; i < length; i++) {
348  kind = secfile_lookup_str_default(file, nullptr, "%s.wl_kind%d",
349  path_str, i);
350 
351  if (!kind) {
352  // before 2.2.0 unit production was indicated by flag.
353  bool is_unit = secfile_lookup_bool_default(
354  file, false, "%s.wl_is_unit%d", path_str, i);
355  kind = universals_n_name(is_unit ? VUT_UTYPE : VUT_IMPROVEMENT);
356  }
357 
358  name = secfile_lookup_str_default(file, nullptr, "%s.wl_value%d",
359  path_str, i);
360  if (nullptr == kind || '\0' == kind[0] || nullptr == name
361  || '\0' == name[0]) {
362  break;
363  } else {
364  pgwl->unbuilt.entries[i].kind = fc_strdup(kind);
365  pgwl->unbuilt.entries[i].name = fc_strdup(name);
366  pgwl->unbuilt.length++;
367  }
368  }
369 
370  return true;
371 }
372 
377 {
378  int i;
379 
380  // Clear the current global worklists.
383 
384  for (i = 0; global_worklist_load(file, "worklists.worklist%d", i); i++) {
385  // Nothing to do more.
386  }
387 
388  if (C_S_RUNNING <= client_state()) {
389  // We need to build the worklists immediately.
391  }
392 }
393 
397 static void global_worklist_save(const struct global_worklist *pgwl,
398  struct section_file *file, int fill_until,
399  const char *path, ...)
400 {
401  char path_str[1024];
402  int i = 0;
403  va_list ap;
404 
405  /* The first part of the registry path is taken from the varargs to the
406  * function. */
407  va_start(ap, path);
408  fc_vsnprintf(path_str, sizeof(path_str), path, ap);
409  va_end(ap);
410 
411  secfile_insert_str(file, pgwl->name, "%s.wl_name", path_str);
412 
413  switch (pgwl->status) {
414  case STATUS_UNBUILT:
415  secfile_insert_int(file, pgwl->unbuilt.length, "%s.wl_length", path_str);
416  for (i = 0; i < pgwl->unbuilt.length; i++) {
417  secfile_insert_str(file, pgwl->unbuilt.entries[i].kind, "%s.wl_kind%d",
418  path_str, i);
419  secfile_insert_str(file, pgwl->unbuilt.entries[i].name,
420  "%s.wl_value%d", path_str, i);
421  }
422  break;
423  case STATUS_WORKLIST:
425  "%s.wl_length", path_str);
426  for (i = 0; i < pgwl->unbuilt.length; i++) {
428  file, universal_type_rule_name(pgwl->worklist.entries + i),
429  "%s.wl_kind%d", path_str, i);
430  secfile_insert_str(file,
432  "%s.wl_value%d", path_str, i);
433  }
434  break;
435  }
436 
437  /* We want to keep savegame in tabular format, so each line has to be
438  * of equal length. Fill table up to maximum worklist size. */
439  while (i < fill_until) {
440  secfile_insert_str(file, "", "%s.wl_kind%d", path_str, i);
441  secfile_insert_str(file, "", "%s.wl_value%d", path_str, i);
442  i++;
443  }
444 }
445 
450 {
451  int max_length = 0;
452  int i = 0;
453 
454  /* We want to keep savegame in tabular format, so each line has to be
455  * of equal length. So we need to know about the biggest worklist. */
457  {
458  switch (pgwl->status) {
459  case STATUS_UNBUILT:
460  max_length = MAX(max_length, pgwl->unbuilt.length);
461  break;
462  case STATUS_WORKLIST:
463  max_length = MAX(max_length, worklist_length(&pgwl->worklist));
464  break;
465  }
466  }
468 
470  {
471  global_worklist_save(pgwl, file, max_length, "worklists.worklist%d",
472  i++);
473  }
475 }
enum client_states client_state()
Return current client state.
struct civclient client
@ C_S_RUNNING
Definition: client_main.h:43
#define MAX_LEN_NAME
Definition: fc_types.h:61
#define _(String)
Definition: fcintl.h:50
struct global_worklist * global_worklist_by_id(int id)
Returns the global worklist corresponding to this id.
static bool static void global_worklist_save(const struct global_worklist *pgwl, struct section_file *file, int fill_until, const char *path,...) fc__attribute((__format__(__printf__
Save one global worklist into a section file.
static bool global_worklist_load(struct section_file *file, const char *path,...) fc__attribute((__format__(__printf__
Load a global worklist form a section file.
bool global_worklist_set(struct global_worklist *pgwl, const struct worklist *pwl)
Sets the worklist.
void global_worklists_build()
Check if the global worklists are valid or not for the ruleset.
int global_worklist_id(const struct global_worklist *pgwl)
Returns the id of the global worklist.
static struct global_worklist * global_worklist_alloc(enum global_worklist_status type)
Returns a new created global worklist structure.
global_worklist_status
@ STATUS_WORKLIST
@ STATUS_UNBUILT
void global_worklists_unbuild()
Convert the universal pointers to strings to work out-ruleset.
void global_worklists_free()
Free the client global worklists.
bool global_worklist_is_valid(const struct global_worklist *pgwl)
Returns TRUE if this global worklist is valid.
void global_worklist_destroy(struct global_worklist *pgwl)
Destroys a glocal worklist.
void global_worklists_load(struct section_file *file)
Load all global worklist from a section file.
struct global_worklist * global_worklist_new(const char *name)
Creates a new global worklist form a normal worklist.
static bool static void void global_worklists_init()
Initialize the client global worklists.
const char * global_worklist_name(const struct global_worklist *pgwl)
Return the name of the global worklist.
const struct worklist * global_worklist_get(const struct global_worklist *pgwl)
Returns the worklist of this global worklist or nullptr if it's not valid.
void global_worklists_save(struct section_file *file)
Save all global worklist into a section file.
void global_worklist_set_name(struct global_worklist *pgwl, const char *name)
Sets the name of this global worklist.
#define global_worklists_iterate_all_end
#define global_worklists_iterate_all(pgwl)
const char * name
Definition: inputfile.cpp:118
#define fc_assert_ret(condition)
Definition: log.h:112
#define fc_assert_ret_val(condition, val)
Definition: log.h:114
bool secfile_lookup_bool_default(const struct section_file *secfile, bool def, const char *path,...)
Lookup a boolean value in the secfile.
const char * secfile_lookup_str_default(const struct section_file *secfile, const char *def, const char *path,...)
Lookup a string value in the secfile.
int secfile_lookup_int_default(const struct section_file *secfile, int def, const char *path,...)
Lookup a integer value in the secfile.
#define secfile_insert_int(secfile, value, path,...)
Definition: registry_ini.h:116
#define secfile_insert_str(secfile, string, path,...)
Definition: registry_ini.h:167
const char * universal_type_rule_name(const struct universal *psource)
Return untranslated name of the universal source name.
const char * universal_rule_name(const struct universal *psource)
Return the (untranslated) rule name of the universal.
struct universal universal_by_rule_name(const char *kind, const char *value)
Parse requirement type (kind) and value strings into a universal structure.
#define MIN(x, y)
Definition: shared.h:49
#define MAX(x, y)
Definition: shared.h:48
struct global_worklist_list * worklists
Definition: client_main.h:90
struct worklist worklist
struct global_worklist::@119::@121 unbuilt
uni_name entries[MAX_LEN_WORKLIST]
enum global_worklist_status status
char name[MAX_LEN_NAME]
enum universals_n kind
Definition: fc_types.h:740
struct universal entries[MAX_LEN_WORKLIST]
Definition: worklist.h:25
int fc_vsnprintf(char *str, size_t n, const char *format, va_list ap)
Definition: support.cpp:512
#define sz_strlcpy(dest, src)
Definition: support.h:140
int fc__attribute((nonnull(1, 3)))
#define fc_strdup(str)
Definition: support.h:111
void worklist_copy(struct worklist *dst, const struct worklist *src)
Copy contents from worklist src to worklist dst.
Definition: worklist.cpp:103
void worklist_init(struct worklist *pwl)
Initialize a worklist to be empty.
Definition: worklist.cpp:32
bool worklist_append(struct worklist *pwl, const struct universal *prod)
Adds the id to the next available slot in the worklist.
Definition: worklist.cpp:138
int worklist_length(const struct worklist *pwl)
Returns the number of entries in the worklist.
Definition: worklist.cpp:51
#define MAX_LEN_WORKLIST
Definition: worklist.h:19