Atrinik Client  4.0
settings.c
Go to the documentation of this file.
1 /*************************************************************************
2  * Atrinik, a Multiplayer Online Role Playing Game *
3  * *
4  * Copyright (C) 2009-2014 Alex Tokar and Atrinik Development Team *
5  * *
6  * Fork from Crossfire (Multiplayer game for X-windows). *
7  * *
8  * This program is free software; you can redistribute it and/or modify *
9  * it under the terms of the GNU General Public License as published by *
10  * the Free Software Foundation; either version 2 of the License, or *
11  * (at your option) any later version. *
12  * *
13  * This program is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16  * GNU General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU General Public License *
19  * along with this program; if not, write to the Free Software *
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
21  * *
22  * The author can be reached at admin@atrinik.org *
23  ************************************************************************/
24 
32 #include <global.h>
33 #include <toolkit/packet.h>
34 #include <toolkit/string.h>
35 #include <toolkit/path.h>
36 
38 static const char *const opt_types[OPT_TYPE_NUM] = {
39  "bool", "input_num", "input_text", "range", "select", "int", "color"
40 };
41 
50 static uint8_t setting_update_mapsize = 0;
51 
59 static void setting_load_value(setting_struct *setting, const char *str)
60 {
61  switch (setting->type) {
62  case OPT_TYPE_BOOL:
63 
64  if (KEYWORD_IS_TRUE(str)) {
65  setting->val.i = 1;
66  } else if (KEYWORD_IS_FALSE(str)) {
67  setting->val.i = 0;
68  } else {
69  setting->val.i = atoi(str);
70  }
71 
72  break;
73 
74  case OPT_TYPE_INPUT_NUM:
75  case OPT_TYPE_RANGE:
76  case OPT_TYPE_INT:
77  case OPT_TYPE_SELECT:
78  setting->val.i = atoi(str);
79  break;
80 
82  case OPT_TYPE_COLOR:
83 
84  if (setting->val.str) {
85  efree(setting->val.str);
86  }
87 
88  setting->val.str = estrdup(str);
89  break;
90  }
91 }
92 
96 void settings_init(void)
97 {
98  FILE *fp;
99  char buf[HUGE_BUF], *cp;
100  setting_category *category;
101  setting_struct *setting;
102 
103  fp = path_fopen(FILE_SETTINGS_TXT, "r");
104 
105  if (!fp) {
106  LOG(ERROR, "Missing "FILE_SETTINGS_TXT ", cannot continue.");
107  exit(1);
108  }
109 
110  category = NULL;
111  setting = NULL;
112  setting_categories = NULL;
114 
115  while (fgets(buf, sizeof(buf) - 1, fp)) {
116  cp = strchr(buf, '\n');
117 
118  if (cp) {
119  *cp = '\0';
120  }
121 
122  cp = buf;
123 
124  while (*cp != '\0') {
125  if (isspace(*cp)) {
126  cp++;
127  } else {
128  break;
129  }
130  }
131 
132  if (*cp == '#' || *cp == '\0') {
133  continue;
134  }
135 
136  if (!strcmp(cp, "end")) {
137  if (setting) {
138  category->settings = erealloc(category->settings, sizeof(*category->settings) * (category->settings_num + 1));
139  category->settings[category->settings_num] = setting;
140  category->settings_num++;
141  setting = NULL;
142  } else if (category) {
143  setting_categories = erealloc(setting_categories, sizeof(*setting_categories) * (setting_categories_num + 1));
144  setting_categories[setting_categories_num] = category;
146  category = NULL;
147  }
148  } else if (setting) {
149  if (!strncmp(cp, "type ", 5)) {
150  size_t type_id;
151 
152  for (type_id = 0; type_id < OPT_TYPE_NUM; type_id++) {
153  if (!strcmp(cp + 5, opt_types[type_id])) {
154  setting->type = type_id;
155  break;
156  }
157  }
158 
159  if (type_id == OPT_TYPE_NUM) {
160  LOG(ERROR, "Invalid type: %s", cp + 5);
161  exit(1);
162  } else if (type_id == OPT_TYPE_SELECT) {
163  setting->custom_attrset = ecalloc(1, sizeof(setting_select));
164  } else if (type_id == OPT_TYPE_RANGE) {
165  setting->custom_attrset = ecalloc(1, sizeof(setting_range));
166  }
167  } else if (!strncmp(cp, "default ", 8)) {
168  setting_load_value(setting, cp + 8);
169  } else if (!strncmp(cp, "desc ", 5)) {
170  setting->desc = estrdup(cp + 5);
171  string_newline_to_literal(setting->desc);
172  } else if (!strncmp(cp, "internal ", 9)) {
173  setting->internal = KEYWORD_IS_TRUE(cp + 9) ? 1 : 0;
174  } else if (setting->type == OPT_TYPE_SELECT && !strncmp(cp, "option ", 7)) {
175  setting_select *s_select = SETTING_SELECT(setting);
176 
177  s_select->options = erealloc(s_select->options, sizeof(*s_select->options) * (s_select->options_len + 1));
178  s_select->options[s_select->options_len] = estrdup(cp + 7);
179  s_select->options_len++;
180  } else if (setting->type == OPT_TYPE_RANGE && !strncmp(cp, "range ", 6)) {
181  setting_range *range = SETTING_RANGE(setting);
182  int64_t min, max;
183 
184  if (sscanf(cp + 6, "%"PRId64 " - %"PRId64, &min, &max) == 2) {
185  range->min = min;
186  range->max = max;
187  } else {
188  LOG(BUG, "Invalid line: %s", cp);
189  }
190  } else if (setting->type == OPT_TYPE_RANGE && !strncmp(cp, "advance ", 8)) {
191  SETTING_RANGE(setting)->advance = atoi(cp + 8);
192  } else {
193  LOG(BUG, "Invalid line: %s", cp);
194  }
195  } else if (category) {
196  if (!strncmp(cp, "setting ", 8)) {
197  setting = ecalloc(1, sizeof(*setting));
198  setting->name = estrdup(cp + 8);
199  } else {
200  LOG(BUG, "Invalid line: %s", cp);
201  }
202  } else if (!strncmp(cp, "category ", 9)) {
203  category = ecalloc(1, sizeof(*category));
204  category->name = estrdup(cp + 9);
205  }
206  }
207 
208  fclose(fp);
209 
210  /* Now load the user's settings (if any). */
211  settings_load();
212 }
213 
217 void settings_load(void)
218 {
219  FILE *fp;
220  char buf[HUGE_BUF], *cp;
221  int64_t cat = 0, setting = 0;
222  uint8_t is_setting_name = 1;
223 
224  fp = path_fopen(FILE_SETTINGS_DAT, "r");
225 
226  /* No user settings yet. */
227  if (!fp) {
228  return;
229  }
230 
231  while (fgets(buf, sizeof(buf) - 1, fp)) {
232  cp = strchr(buf, '\n');
233 
234  if (cp) {
235  *cp = '\0';
236  }
237 
238  cp = buf;
239 
240  while (*cp != '\0') {
241  if (isspace(*cp)) {
242  cp++;
243  } else {
244  break;
245  }
246  }
247 
248  if (*cp == '\0') {
249  continue;
250  }
251 
252  if (!strncmp(cp, "category ", 9)) {
253  cat = category_from_name(cp + 9);
254  } else {
255  if (is_setting_name) {
256  setting = setting_from_name(cp);
257  } else {
258  if (cat != -1 && setting != -1) {
259  setting_load_value(setting_categories[cat]->settings[setting], cp);
260  }
261  }
262 
263  is_setting_name = !is_setting_name;
264  }
265  }
266 
267  fclose(fp);
268 }
269 
273 void settings_save(void)
274 {
275  FILE *fp;
276  size_t cat, set;
277  setting_struct *setting;
278 
279  fp = path_fopen(FILE_SETTINGS_DAT, "w");
280 
281  if (!fp) {
282  LOG(BUG, "Could not open settings file ("FILE_SETTINGS_DAT ").");
283  return;
284  }
285 
286  for (cat = 0; cat < setting_categories_num; cat++) {
287  fprintf(fp, "category %s\n", setting_categories[cat]->name);
288 
289  for (set = 0; set < setting_categories[cat]->settings_num; set++) {
290  setting = setting_categories[cat]->settings[set];
291 
292  fprintf(fp, "%s\n", setting->name);
293 
294  if (setting_is_text(setting)) {
295  fprintf(fp, "%s\n", setting->val.str);
296  } else {
297  fprintf(fp, "%"PRId64 "\n", setting->val.i);
298  }
299  }
300  }
301 
302  fclose(fp);
303 }
304 
310 void settings_deinit(void)
311 {
312  size_t cat, setting;
313 
314  /* Save the user's settings first. */
315  settings_save();
316 
317  /* Start deinitializing. */
318  for (cat = 0; cat < setting_categories_num; cat++) {
319  for (setting = 0; setting < setting_categories[cat]->settings_num; setting++) {
320  if (setting_is_text(setting_categories[cat]->settings[setting])) {
321  efree(setting_categories[cat]->settings[setting]->val.str);
322  }
323 
324  efree(setting_categories[cat]->settings[setting]->name);
325 
326  if (setting_categories[cat]->settings[setting]->desc) {
327  efree(setting_categories[cat]->settings[setting]->desc);
328  }
329 
330  if (setting_categories[cat]->settings[setting]->type == OPT_TYPE_SELECT) {
331  setting_select *s_select = SETTING_SELECT(setting_categories[cat]->settings[setting]);
332  size_t option;
333 
334  for (option = 0; option < s_select->options_len; option++) {
335  efree(s_select->options[option]);
336  }
337 
338  if (s_select->options) {
339  efree(s_select->options);
340  }
341  }
342 
343  if (setting_categories[cat]->settings[setting]->custom_attrset) {
344  efree(setting_categories[cat]->settings[setting]->custom_attrset);
345  }
346 
347  efree(setting_categories[cat]->settings[setting]);
348  }
349 
350  if (setting_categories[cat]->settings) {
351  efree(setting_categories[cat]->settings);
352  }
353 
354  efree(setting_categories[cat]->name);
355  efree(setting_categories[cat]);
356  }
357 
358  if (setting_categories) {
359  efree(setting_categories);
360  setting_categories = NULL;
361  }
362 
363  setting_categories_num = 0;
364 }
365 
374 {
375  switch (setting->type) {
376  case OPT_TYPE_BOOL:
377  case OPT_TYPE_INPUT_NUM:
378  case OPT_TYPE_RANGE:
379  case OPT_TYPE_INT:
380  case OPT_TYPE_SELECT:
381  return &setting->val.i;
382 
383  case OPT_TYPE_INPUT_TEXT:
384  case OPT_TYPE_COLOR:
385  return setting->val.str;
386  }
387 
388  return NULL;
389 }
390 
400 const char *setting_get_str(int cat, int setting)
401 {
402  return setting_get(setting_categories[cat]->settings[setting]);
403 }
404 
414 int64_t setting_get_int(int cat, int setting)
415 {
416  return *(int64_t *) setting_get(setting_categories[cat]->settings[setting]);
417 }
418 
429 static int setting_apply_always(int cat, int setting)
430 {
431  switch (cat) {
432  case OPT_CAT_CLIENT:
433  switch (setting) {
434  /* Need to hide/show the network graph widget. */
436  WIDGET_SHOW_CHANGE(NETWORK_GRAPH_ID, setting_get_int(cat, setting));
437  return 1;
438 
439  case OPT_SYSTEM_CURSOR:
440  SDL_ShowCursor(setting_get_int(cat, setting));
441  return 1;
442  }
443 
444  break;
445 
446  case OPT_CAT_DEVEL:
447  switch (setting) {
448  /* Need to hide/show the fps widget. */
449  case OPT_SHOW_FPS:
450  WIDGET_SHOW_CHANGE(FPS_ID, setting_get_int(cat, setting));
451  return 1;
452  }
453 
454  break;
455  }
456 
457  return 0;
458 }
459 
467 static void setting_apply_runtime(int cat, int setting)
468 {
469  /* Try both run-time and startup-time changes first. */
470  if (setting_apply_always(cat, setting)) {
471  return;
472  }
473 
474  switch (cat) {
475  case OPT_CAT_GENERAL:
476  switch (setting) {
477  /* Changed how exp display shows its data, redraw the
478  * widget. */
479  case OPT_EXP_DISPLAY:
480  break;
481  }
482 
483  break;
484 
485  case OPT_CAT_CLIENT:
486  switch (setting) {
487  /* Resolution change. */
488  case OPT_RESOLUTION:
489  {
490  int w, h;
491 
492  if (sscanf(SETTING_SELECT(setting_categories[cat]->settings[setting])->options[setting_get_int(cat, setting)], "%dx%d", &w, &h) == 2 && (ScreenSurface->w != w || ScreenSurface->h != h)) {
493  resize_window(w, h);
494  video_set_size();
495  }
496 
497  break;
498  }
499 
500  /* Fullscreen change. */
501  case OPT_FULLSCREEN:
502 
503  if ((setting_get_int(cat, setting) && !(ScreenSurface->flags & SDL_FULLSCREEN)) || (!setting_get_int(cat, setting) && ScreenSurface->flags & SDL_FULLSCREEN)) {
505  }
506 
507  break;
508  }
509 
510  break;
511 
512  case OPT_CAT_MAP:
513  switch (setting) {
514  /* Map width/height change. */
515  case OPT_MAP_WIDTH:
516  case OPT_MAP_HEIGHT:
517 
519  int w, h;
520  packet_struct *packet;
521 
522  w = setting_get_int(cat, OPT_MAP_WIDTH);
524 
525  packet = packet_new(SERVER_CMD_SETUP, 32, 0);
526  packet_append_uint8(packet, CMD_SETUP_MAPSIZE);
527  packet_append_uint8(packet, w);
528  packet_append_uint8(packet, h);
529  socket_send_packet(packet);
530 
531  map_update_size(w, h);
532 
534  }
535 
536  break;
537  }
538 
539  break;
540 
541  case OPT_CAT_SOUND:
542  switch (setting) {
543  /* Music volume change. */
544  case OPT_VOLUME_MUSIC:
546  break;
547  }
548 
549  break;
550  }
551 }
552 
557 void settings_apply(void)
558 {
559  size_t i, j;
560 
561  for (i = 0; i < setting_categories_num; i++) {
562  for (j = 0; j < setting_categories[i]->settings_num; j++) {
563  setting_apply_always(i, j);
564  }
565  }
566 }
567 
573 {
574  size_t cat, setting;
575 
576  for (cat = 0; cat < setting_categories_num; cat++) {
577  for (setting = 0; setting < setting_categories[cat]->settings_num; setting++) {
578  setting_apply_runtime(cat, setting);
579  }
580  }
581 }
582 
592 void setting_set_int(int cat, int setting, int64_t val)
593 {
594  void *dst = setting_get(setting_categories[cat]->settings[setting]);
595  if ((*(int64_t *) dst) == val) {
596  return;
597  }
598 
599  (*(int64_t *) dst) = val;
600 
601  /* Map width/height, mark for update. */
602  if (cat == OPT_CAT_MAP && (setting == OPT_MAP_WIDTH || setting == OPT_MAP_HEIGHT)) {
604  }
605 }
606 
616 void setting_set_str(int cat, int setting, const char *val)
617 {
618  setting_struct *set;
619 
620  set = setting_categories[cat]->settings[setting];
621 
622  if (set->val.str) {
623  efree(set->val.str);
624  }
625 
626  set->val.str = estrdup(val);
627 }
628 
637 {
638  switch (setting->type) {
639  case OPT_TYPE_INPUT_TEXT:
640  case OPT_TYPE_COLOR:
641  return 1;
642  }
643 
644  return 0;
645 }
646 
654 int64_t category_from_name(const char *name)
655 {
656  size_t cat;
657 
658  for (cat = 0; cat < setting_categories_num; cat++) {
659  if (!strcmp(setting_categories[cat]->name, name)) {
660  return cat;
661  }
662  }
663 
664  return -1;
665 }
666 
676 int64_t setting_from_name(const char *name)
677 {
678  size_t cat, setting;
679 
680  for (cat = 0; cat < setting_categories_num; cat++) {
681  for (setting = 0; setting < setting_categories[cat]->settings_num; setting++) {
682  if (!strcmp(setting_categories[cat]->settings[setting]->name, name)) {
683  return setting;
684  }
685  }
686  }
687 
688  return -1;
689 }
static void setting_load_value(setting_struct *setting, const char *str)
Definition: settings.c:59
void sound_update_volume(void)
Definition: sound.c:547
static uint8_t setting_update_mapsize
Definition: settings.c:50
void settings_init(void)
Definition: settings.c:96
int64_t min
Definition: settings.h:183
union setting_struct::@30 val
uint8_t type
Definition: settings.h:215
void settings_apply_change(void)
Definition: settings.c:572
int video_fullscreen_toggle(SDL_Surface **surface, uint32_t *flags)
Definition: video.c:392
void setting_set_int(int cat, int setting, int64_t val)
Definition: settings.c:592
#define FILE_SETTINGS_TXT
Definition: config.h:47
void setting_set_str(int cat, int setting, const char *val)
Definition: settings.c:616
int64_t category_from_name(const char *name)
Definition: settings.c:654
SDL_Surface * ScreenSurface
Definition: main.c:47
char * str
Definition: settings.h:226
int64_t setting_from_name(const char *name)
Definition: settings.c:676
void * custom_attrset
Definition: settings.h:221
void * setting_get(setting_struct *setting)
Definition: settings.c:373
setting_category ** setting_categories
Definition: settings.c:43
char * desc
Definition: settings.h:212
size_t setting_categories_num
Definition: settings.c:45
int64_t setting_get_int(int cat, int setting)
Definition: settings.c:414
setting_struct ** settings
Definition: settings.h:241
void resize_window(int width, int height)
Definition: event.c:115
const char * setting_get_str(int cat, int setting)
Definition: settings.c:400
int video_set_size(void)
Definition: video.c:344
void settings_load(void)
Definition: settings.c:217
int64_t i
Definition: settings.h:229
int setting_is_text(setting_struct *setting)
Definition: settings.c:636
void settings_deinit(void)
Definition: settings.c:310
void map_update_size(int w, int h)
Definition: map.c:190
#define FILE_SETTINGS_DAT
Definition: config.h:49
char * name
Definition: settings.h:209
uint8_t internal
Definition: settings.h:218
void settings_apply(void)
Definition: settings.c:557
static void setting_apply_runtime(int cat, int setting)
Definition: settings.c:467
char ** options
Definition: settings.h:198
#define SETTING_RANGE(_setting)
Definition: settings.h:250
#define SETTING_SELECT(_setting)
Definition: settings.h:248
size_t settings_num
Definition: settings.h:244
int64_t max
Definition: settings.h:186
static int setting_apply_always(int cat, int setting)
Definition: settings.c:429
size_t options_len
Definition: settings.h:201
void settings_save(void)
Definition: settings.c:273
static const char *const opt_types[OPT_TYPE_NUM]
Definition: settings.c:38