Atrinik Client  4.0
upgrader.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 
38 static const char *const client_versions[] = {
39  "2.0", "2.5", "3.0"
40 };
41 
43 static int64_t version_id_migrating = -1;
44 
55 static void upgrade_20_to_25(const char *from, const char *to)
56 {
57  char src[MAX_BUF], buf[HUGE_BUF];
58  FILE *fp;
59 
60  /* Try to upgrade keybindings, if they exist. */
61  snprintf(src, sizeof(src), "%s/keys.dat", from);
62  fp = fopen(src, "r");
63 
64  if (fp) {
65  int keycode, repeat;
66  char keyname[MAX_BUF], command[HUGE_BUF];
67 
68  keybind_load();
69 
70  /* Read the old keys.dat file. */
71  while (fgets(buf, sizeof(buf) - 1, fp)) {
72  /* Try to parse the macro definition lines. */
73  if (sscanf(buf, "%d %d \"%200[^\"]\" \"%2000[^\"]\"", &keycode, &repeat, keyname, command) == 4) {
74  keybind_struct *keybind;
75 
76  /* Is it a command? */
77  if (*command == '/') {
78  keybind = keybind_find_by_command(command);
79 
80  /* Does not exist yet, add it. */
81  if (!keybind) {
82  keybind = keybind_add(keycode, 0, command);
83  } else {
84  keybind->key = keycode;
85  }
86 
87  keybind->repeat = repeat;
88  } else if (!strncmp(command, "?M_MCON", 7)) {
89  char mcon_buf[HUGE_BUF];
90 
91  snprintf(mcon_buf, sizeof(mcon_buf), "?MCON %s", command + 7);
92 
93  if (!keybind_find_by_command(mcon_buf)) {
94  keybind = keybind_add(keycode, 0, mcon_buf);
95  keybind->repeat = repeat;
96  }
97  } else if (*command == '?') {
98  const char *new_cmd = command;
99 
100  if (!strcmp(command, "?M_NORTH")) {
101  new_cmd = "?MOVE_N";
102  } else if (!strcmp(command, "?M_NORTHEAST")) {
103  new_cmd = "?MOVE_NE";
104  } else if (!strcmp(command, "?M_EAST")) {
105  new_cmd = "?MOVE_E";
106  } else if (!strcmp(command, "?M_SOUTHEAST")) {
107  new_cmd = "?MOVE_SE";
108  } else if (!strcmp(command, "?M_SOUTH")) {
109  new_cmd = "?MOVE_S";
110  } else if (!strcmp(command, "?M_SOUTHWEST")) {
111  new_cmd = "?MOVE_SW";
112  } else if (!strcmp(command, "?M_WEST")) {
113  new_cmd = "?MOVE_W";
114  } else if (!strcmp(command, "?M_NORTHWEST")) {
115  new_cmd = "?MOVE_NW";
116  } else if (!strcmp(command, "?M_STAY")) {
117  new_cmd = "?MOVE_STAY";
118  } else if (!strcmp(command, "?M_UP")) {
119  new_cmd = "?UP";
120  } else if (!strcmp(command, "?M_DOWN")) {
121  new_cmd = "?DOWN";
122  } else if (!strcmp(command, "?M_LEFT")) {
123  new_cmd = "?LEFT";
124  } else if (!strcmp(command, "?M_RIGHT")) {
125  new_cmd = "?RIGHT";
126  } else if (!strcmp(command, "?M_SPELL_LIST")) {
127  new_cmd = "?SPELL_LIST";
128  } else if (!strcmp(command, "?M_SKILL_LIST")) {
129  new_cmd = "?SKILL_LIST";
130  } else if (!strcmp(command, "?M_HELP")) {
131  new_cmd = "?HELP";
132  } else if (!strcmp(command, "?M_KEYBIND")) {
133  new_cmd = "?PARTY_LIST";
134  } else if (!strcmp(command, "?M_QLIST")) {
135  new_cmd = "?QLIST";
136  } else if (!strcmp(command, "?M_RANGE")) {
137  new_cmd = "?RANGE";
138  } else if (!strcmp(command, "?M_FIRE_READY")) {
139  new_cmd = "?FIRE_READY";
140  } else if (!strcmp(command, "?M_TARGET_ENEMY")) {
141  new_cmd = "?TARGET_ENEMY";
142  } else if (!strcmp(command, "?M_TARGET_FRIEND")) {
143  new_cmd = "?TARGET_FRIEND";
144  } else {
145  continue;
146  }
147 
148  keybind = keybind_find_by_command(new_cmd);
149 
150  if (keybind) {
151  keybind->key = keycode;
152  }
153  }
154  }
155  }
156 
157  keybind_deinit();
158  fclose(fp);
159  }
160 
161  /* Try to upgrade options. */
162  snprintf(src, sizeof(src), "%s/options.dat", from);
163  fp = fopen(src, "r");
164 
165  if (fp) {
166  char option_name[MAX_BUF];
167  int option_value;
168 
169  settings_init();
170 
171  /* Read the old options.dat file. */
172  while (fgets(buf, sizeof(buf) - 1, fp)) {
173  /* Handle the x/y options. */
174  if (!strncmp(buf, "%3x ", 4)) {
176  continue;
177  } else if (!strncmp(buf, "%3y ", 4)) {
179  continue;
180  }
181 
182  /* Parse the option lines. */
183  if (sscanf(buf, "%200[^:]: %d", option_name, &option_value) == 2) {
184  int cat = -1, setting = -1;
185 
186  if (!strcmp(option_name, "Show yourself targeted")) {
187  cat = OPT_CAT_GENERAL;
188  setting = OPT_TARGET_SELF;
189  } else if (!strcmp(option_name, "Collect mode")) {
190  cat = OPT_CAT_GENERAL;
191  setting = OPT_COLLECT_MODE;
192  } else if (!strcmp(option_name, "Exp display")) {
193  cat = OPT_CAT_GENERAL;
194  setting = OPT_EXP_DISPLAY;
195  } else if (!strcmp(option_name, "Chat Timestamps")) {
196  cat = OPT_CAT_GENERAL;
197  setting = OPT_CHAT_TIMESTAMPS;
198  } else if (!strcmp(option_name, "Maximum chat lines")) {
199  cat = OPT_CAT_GENERAL;
200  setting = OPT_MAX_CHAT_LINES;
201  } else if (!strcmp(option_name, "Fullscreen")) {
202  cat = OPT_CAT_CLIENT;
203  setting = OPT_FULLSCREEN;
204  } else if (!strcmp(option_name, "Resolution")) {
205  cat = OPT_CAT_CLIENT;
206  setting = OPT_RESOLUTION;
207  } else if (!strcmp(option_name, "Player Names")) {
208  cat = OPT_CAT_MAP;
209  setting = OPT_PLAYER_NAMES;
210  } else if (!strcmp(option_name, "Playfield zoom")) {
211  cat = OPT_CAT_MAP;
212  setting = OPT_MAP_ZOOM;
213  } else if (!strcmp(option_name, "Low health warning")) {
214  cat = OPT_CAT_MAP;
215  setting = OPT_HEALTH_WARNING;
216  } else if (!strcmp(option_name, "Low food warning")) {
217  cat = OPT_CAT_MAP;
218  setting = OPT_FOOD_WARNING;
219  } else if (!strcmp(option_name, "Sound volume")) {
220  cat = OPT_CAT_SOUND;
221  setting = OPT_VOLUME_SOUND;
222  } else if (!strcmp(option_name, "Music volume")) {
223  cat = OPT_CAT_SOUND;
224  setting = OPT_VOLUME_MUSIC;
225  } else if (!strcmp(option_name, "Show Framerate")) {
226  cat = OPT_CAT_DEVEL;
227  setting = OPT_SHOW_FPS;
228  } else if (!strcmp(option_name, "Enable quickport")) {
229  cat = OPT_CAT_DEVEL;
230  setting = OPT_OPERATOR;
231  }
232 
233  if (cat != -1 && setting != -1) {
234  setting_set_int(cat, setting, option_value);
235  }
236  }
237  }
238 
239  settings_deinit();
240  fclose(fp);
241  }
242 
243  /* interface.gui and scripts_autoload changed locations in 2.5, copy
244  * them to the correct new location. */
245  copy_if_exists(from, to, "interface.gui", "settings/interface.gui");
246  copy_if_exists(from, to, "scripts_autoload", "settings/scripts_autoload");
247  /* Copy over settings directory - in 2.0 and before only used to have
248  * ignore lists. */
249  copy_if_exists(from, to, "settings", "settings");
250 }
251 
259 static void upgrade_25_to_30(const char *from, const char *to)
260 {
261  copy_if_exists(from, to, "settings", "settings");
262 }
263 
268 void upgrader_init(void)
269 {
270  char tmp[HUGE_BUF], tmp2[HUGE_BUF], version[MAX_BUF];
271  size_t i;
272 
274  snprintf(tmp, sizeof(tmp), "%s/.atrinik", get_config_dir());
275 
276  /* The .atrinik directory doesn't exist yet, nothing to migrate. */
277  if (access(tmp, R_OK) != 0) {
278  return;
279  }
280 
281  snprintf(tmp, sizeof(tmp), "%s/.atrinik/%s", get_config_dir(), package_get_version_partial(version, sizeof(version)));
282 
283  /* If the settings directory for the current version already exists,
284  * leave. */
285  if (access(tmp, R_OK) == 0) {
286  return;
287  }
288 
289  /* Look through the client versions, but skip the last entry, which
290  * should be the current version.
291  *
292  * The logic is that the upgrader will attempt to go through each
293  * version, and migrate settings into the next version. For example,
294  * 2.0 -> 2.5, 2.5 -> 3.0, etc. */
295  for (i = 0; i < arraysize(client_versions) - 1; i++) {
296  /* Construct the paths to the version we're looking at in the
297  * array, and the version after that. */
298  snprintf(tmp, sizeof(tmp), "%s/.atrinik/%s", get_config_dir(), client_versions[i]);
299  snprintf(tmp2, sizeof(tmp2), "%s/.atrinik/%s", get_config_dir(), client_versions[i + 1]);
300 
301  /* Only migrate if the settings for the version we're looking at
302  * exist, and the next version directory does not exist. */
303  if (access(tmp, R_OK) != 0 || access(tmp2, R_OK) == 0) {
304  continue;
305  }
306 
307  /* Create the new version directory. */
308  mkdir(tmp2, 0755);
309 
311 
312  /* Migrate 2.0 to 2.5. */
313  if (!strcmp(client_versions[i], "2.0")) {
314  upgrade_20_to_25(tmp, tmp2);
315  } else if (!strcmp(client_versions[i], "2.5")) {
316  upgrade_25_to_30(tmp, tmp2);
317  }
318  }
319 
321 }
322 
332 char *upgrader_get_version_partial(char *dst, size_t dstlen)
333 {
334  /* No version is being migrated. */
335  if (version_id_migrating == -1) {
336  return NULL;
337  }
338 
339  strncpy(dst, client_versions[version_id_migrating], dstlen - 1);
340  dst[dstlen - 1] = '\0';
341 
342  return dst;
343 }
void settings_init(void)
Definition: settings.c:96
static const char *const client_versions[]
Definition: upgrader.c:38
void copy_if_exists(const char *from, const char *to, const char *src, const char *dst)
Definition: wrapper.c:194
static int64_t version_id_migrating
Definition: upgrader.c:43
static void upgrade_25_to_30(const char *from, const char *to)
Definition: upgrader.c:259
void setting_set_int(int cat, int setting, int64_t val)
Definition: settings.c:592
char * package_get_version_partial(char *dst, size_t dstlen)
Definition: misc.c:89
void keybind_load(void)
Definition: keybind.c:60
uint8_t repeat
Definition: keybind.h:50
SDLKey key
Definition: keybind.h:44
void keybind_deinit(void)
Definition: keybind.c:168
keybind_struct * keybind_add(SDLKey key, SDLMod mod, const char *command)
Definition: keybind.c:237
keybind_struct * keybind_find_by_command(const char *cmd)
Definition: keybind.c:371
void settings_deinit(void)
Definition: settings.c:310
static void upgrade_20_to_25(const char *from, const char *to)
Definition: upgrader.c:55
char * upgrader_get_version_partial(char *dst, size_t dstlen)
Definition: upgrader.c:332
void upgrader_init(void)
Definition: upgrader.c:268
const char * get_config_dir(void)
Definition: wrapper.c:303