1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/tools/installer/GamesList.cpp Sun Mar 30 07:00:22 2008 +0000
1.3 @@ -0,0 +1,574 @@
1.4 +#include "GamesList.h"
1.5 +#include "InstallerUtil.h"
1.6 +#include "InstallerMain.h"
1.7 +#include <stdio.h>
1.8 +
1.9 +game_database_t g_games =
1.10 +{
1.11 + NULL, 0,
1.12 + {NULL, 0, GAME_LIST_NO_GAMES},
1.13 + {NULL, 0, GAME_LIST_NO_GAMES},
1.14 + {NULL, 0, GAME_LIST_NO_GAMES}
1.15 +};
1.16 +
1.17 +valve_game_t valve_game_list[] =
1.18 +{
1.19 + {_T("counter-strike source"), _T("cstrike"), SOURCE_ENGINE_2004},
1.20 + {_T("day of defeat source"), _T("dod"), SOURCE_ENGINE_2004},
1.21 + {_T("half-life 2 deathmatch"), _T("hl2mp"), SOURCE_ENGINE_2004},
1.22 + {_T("half-life deathmatch source"), _T("hl1mp"), SOURCE_ENGINE_2004},
1.23 + {_T("team fortress 2"), _T("tf"), SOURCE_ENGINE_2007},
1.24 + {NULL, NULL, 0},
1.25 +};
1.26 +
1.27 +valve_game_t valve_server_list[] =
1.28 +{
1.29 + {_T("source dedicated server"), NULL, SOURCE_ENGINE_2004},
1.30 + {_T("source 2007 dedicated server"), NULL, SOURCE_ENGINE_2007},
1.31 + {NULL, NULL, 0},
1.32 +};
1.33 +
1.34 +int IsValidFolder(const TCHAR *path)
1.35 +{
1.36 + DWORD attr;
1.37 + TCHAR gameinfo_file[MAX_PATH];
1.38 +
1.39 + UTIL_PathFormat(gameinfo_file, sizeof(gameinfo_file), _T("%s\\gameinfo.txt"), path);
1.40 +
1.41 + if ((attr = GetFileAttributes(gameinfo_file)) == INVALID_FILE_ATTRIBUTES)
1.42 + {
1.43 + return GAMEINFO_DOES_NOT_EXIST;
1.44 + }
1.45 +
1.46 + if ((attr & FILE_ATTRIBUTE_READONLY) == FILE_ATTRIBUTE_READONLY)
1.47 + {
1.48 + return GAMEINFO_IS_READ_ONLY;
1.49 + }
1.50 +
1.51 + if ((attr & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)
1.52 + {
1.53 + return GAMEINFO_DOES_NOT_EXIST;
1.54 + }
1.55 +
1.56 + return GAMEINFO_IS_USABLE;
1.57 +}
1.58 +
1.59 +void DisplayBadFolderDialog(HWND hDlg, int reason)
1.60 +{
1.61 + TCHAR message_string[255];
1.62 + UINT resource;
1.63 +
1.64 + if (reason == GAMEINFO_DOES_NOT_EXIST)
1.65 + {
1.66 + resource = IDS_NO_GAMEINFO;
1.67 + }
1.68 + else if (reason == GAMEINFO_IS_READ_ONLY)
1.69 + {
1.70 + resource = IDS_READONLY_GAMEINFO;
1.71 + }
1.72 + else
1.73 + {
1.74 + return;
1.75 + }
1.76 +
1.77 + if (LoadString(g_hInstance,
1.78 + resource,
1.79 + message_string,
1.80 + sizeof(message_string) / sizeof(TCHAR)
1.81 + ) == 0)
1.82 + {
1.83 + return;
1.84 + }
1.85 +
1.86 + MessageBox(hDlg,
1.87 + message_string,
1.88 + _T("SourceMod Installer"),
1.89 + MB_OK|MB_ICONWARNING);
1.90 +}
1.91 +
1.92 +game_list_t *MakeGameList(const TCHAR *name)
1.93 +{
1.94 + game_list_t *gl = (game_list_t *)malloc(sizeof(game_list_t));
1.95 +
1.96 + UTIL_Format(gl->root_name,
1.97 + sizeof(gl->root_name) / sizeof(TCHAR),
1.98 + _T("%s"),
1.99 + name);
1.100 + gl->game_count = 0;
1.101 + gl->games = NULL;
1.102 +
1.103 + return gl;
1.104 +}
1.105 +
1.106 +void AttachGameListToGroup(game_group_t *group, game_list_t *gl)
1.107 +{
1.108 + if (group->lists == NULL)
1.109 + {
1.110 + group->lists = (game_list_t **)malloc(sizeof(game_list_t *));
1.111 + }
1.112 + else
1.113 + {
1.114 + group->lists = (game_list_t **)realloc(group->lists,
1.115 + sizeof(game_list_t *) * (group->list_count + 1));
1.116 + }
1.117 +
1.118 + group->lists[group->list_count] = gl;
1.119 + group->list_count++;
1.120 +}
1.121 +
1.122 +void AttachModToGameList(game_list_t *gl, unsigned int mod_id)
1.123 +{
1.124 + if (gl->games == NULL)
1.125 + {
1.126 + gl->games = (unsigned int *)malloc(sizeof(unsigned int));
1.127 + }
1.128 + else
1.129 + {
1.130 + gl->games = (unsigned int *)realloc(gl->games,
1.131 + sizeof(unsigned int) * (gl->game_count + 1));
1.132 + }
1.133 +
1.134 + gl->games[gl->game_count] = mod_id;
1.135 + gl->game_count++;
1.136 +}
1.137 +
1.138 +unsigned int AddModToList(game_database_t *db, const game_info_t *mod_info)
1.139 +{
1.140 + /* Check if a matching game already exists */
1.141 + for (unsigned int i = 0; i < db->game_count; i++)
1.142 + {
1.143 + if (tstrcasecmp(mod_info->game_path, db->game_list[i].game_path) == 0)
1.144 + {
1.145 + return i;
1.146 + }
1.147 + }
1.148 +
1.149 + if (db->game_list == NULL)
1.150 + {
1.151 + db->game_list = (game_info_t *)malloc(sizeof(game_info_t));
1.152 + }
1.153 + else
1.154 + {
1.155 + db->game_list = (game_info_t *)realloc(db->game_list,
1.156 + sizeof(game_info_t) * (db->game_count + 1));
1.157 + }
1.158 +
1.159 + memcpy(&db->game_list[db->game_count], mod_info, sizeof(game_info_t));
1.160 + db->game_count++;
1.161 +
1.162 + return db->game_count - 1;
1.163 +}
1.164 +
1.165 +bool TryToAddMod(const TCHAR *path, int eng_type, game_database_t *db, unsigned int *id)
1.166 +{
1.167 + FILE *fp;
1.168 + TCHAR gameinfo_path[MAX_PATH];
1.169 +
1.170 + UTIL_PathFormat(gameinfo_path,
1.171 + sizeof(gameinfo_path),
1.172 + _T("%s\\gameinfo.txt"),
1.173 + path);
1.174 +
1.175 + if ((fp = _tfopen(gameinfo_path, _T("rt"))) == NULL)
1.176 + {
1.177 + return false;
1.178 + }
1.179 +
1.180 + int pos;
1.181 + char buffer[512];
1.182 + char key[256], value[256];
1.183 + while (!feof(fp) && fgets(buffer, sizeof(buffer), fp) != NULL)
1.184 + {
1.185 + if ((pos = BreakStringA(buffer, key, sizeof(key))) == -1)
1.186 + {
1.187 + continue;
1.188 + }
1.189 + if ((pos = BreakStringA(&buffer[pos], value, sizeof(value))) == -1)
1.190 + {
1.191 + continue;
1.192 + }
1.193 + if (strcmp(key, "game") == 0)
1.194 + {
1.195 + game_info_t mod;
1.196 + unsigned int got_id;
1.197 +
1.198 + AnsiToUnicode(value, mod.name, sizeof(mod.name));
1.199 + UTIL_Format(mod.game_path, sizeof(mod.game_path), _T("%s"), path);
1.200 + mod.source_engine = eng_type;
1.201 +
1.202 + got_id = AddModToList(db, &mod);
1.203 +
1.204 + if (id != NULL)
1.205 + {
1.206 + *id = got_id;
1.207 + }
1.208 +
1.209 + fclose(fp);
1.210 +
1.211 + return true;
1.212 + }
1.213 + }
1.214 +
1.215 + fclose(fp);
1.216 +
1.217 + return false;
1.218 +}
1.219 +
1.220 +void AddModsFromFolder(const TCHAR *path,
1.221 + int eng_type,
1.222 + game_database_t *db,
1.223 + game_list_t *gl)
1.224 +{
1.225 + HANDLE hFind;
1.226 + WIN32_FIND_DATA fd;
1.227 + TCHAR temp_path[MAX_PATH];
1.228 + TCHAR search_path[MAX_PATH];
1.229 + unsigned int mod_id;
1.230 +
1.231 + UTIL_Format(search_path,
1.232 + sizeof(search_path),
1.233 + _T("%s\\*.*"),
1.234 + path);
1.235 +
1.236 + if ((hFind = FindFirstFile(search_path, &fd)) == INVALID_HANDLE_VALUE)
1.237 + {
1.238 + return;
1.239 + }
1.240 +
1.241 + do
1.242 + {
1.243 + if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY)
1.244 + {
1.245 + continue;
1.246 + }
1.247 +
1.248 + if (tstrcasecmp(fd.cFileName, _T(".")) == 0
1.249 + || tstrcasecmp(fd.cFileName, _T("..")) == 0)
1.250 + {
1.251 + continue;
1.252 + }
1.253 +
1.254 + UTIL_PathFormat(temp_path,
1.255 + sizeof(temp_path),
1.256 + _T("%s\\%s"),
1.257 + path,
1.258 + fd.cFileName);
1.259 + if (TryToAddMod(temp_path, eng_type, db, &mod_id))
1.260 + {
1.261 + AttachModToGameList(gl, mod_id);
1.262 + }
1.263 + } while (FindNextFile(hFind, &fd));
1.264 +
1.265 + FindClose(hFind);
1.266 +}
1.267 +
1.268 +void GetSteamGames(game_database_t *db)
1.269 +{
1.270 + HKEY hkPath;
1.271 + DWORD dwLen, dwType;
1.272 + HANDLE hFind;
1.273 + WIN32_FIND_DATA fd;
1.274 + TCHAR temp_path[MAX_PATH];
1.275 + TCHAR steam_path[MAX_PATH];
1.276 + TCHAR steamapps_path[MAX_PATH];
1.277 +
1.278 + if (RegOpenKeyEx(HKEY_CURRENT_USER,
1.279 + _T("Software\\Valve\\Steam"),
1.280 + 0,
1.281 + KEY_READ,
1.282 + &hkPath) != ERROR_SUCCESS)
1.283 + {
1.284 + db->listen.error_code = GAME_LIST_CANT_READ;
1.285 + db->dedicated.error_code = GAME_LIST_CANT_READ;
1.286 + return;
1.287 + }
1.288 +
1.289 + dwLen = sizeof(steam_path) / sizeof(TCHAR);
1.290 + if (RegQueryValueEx(hkPath,
1.291 + _T("SteamPath"),
1.292 + NULL,
1.293 + &dwType,
1.294 + (LPBYTE)steam_path,
1.295 + &dwLen) != ERROR_SUCCESS)
1.296 + {
1.297 + RegCloseKey(hkPath);
1.298 + db->listen.error_code = GAME_LIST_CANT_READ;
1.299 + db->dedicated.error_code = GAME_LIST_CANT_READ;
1.300 + return;
1.301 + }
1.302 +
1.303 + UTIL_PathFormat(steamapps_path,
1.304 + sizeof(steamapps_path) / sizeof(TCHAR),
1.305 + _T("%s\\steamapps\\*.*"),
1.306 + steam_path);
1.307 +
1.308 + if ((hFind = FindFirstFile(steamapps_path, &fd)) == INVALID_HANDLE_VALUE)
1.309 + {
1.310 + RegCloseKey(hkPath);
1.311 + db->listen.error_code = GAME_LIST_CANT_READ;
1.312 + db->dedicated.error_code = GAME_LIST_CANT_READ;
1.313 + return;
1.314 + }
1.315 +
1.316 + do
1.317 + {
1.318 + if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY)
1.319 + {
1.320 + continue;
1.321 + }
1.322 +
1.323 + if (tstrcasecmp(fd.cFileName, _T(".")) == 0
1.324 + || tstrcasecmp(fd.cFileName, _T("..")) == 0)
1.325 + {
1.326 + continue;
1.327 + }
1.328 +
1.329 + /* If we get a folder called "SourceMods," look for third party mods */
1.330 + if (tstrcasecmp(fd.cFileName, _T("SourceMods")) == 0)
1.331 + {
1.332 + game_list_t *gl = MakeGameList(_T("Third-Party Games"));
1.333 +
1.334 + UTIL_PathFormat(temp_path,
1.335 + sizeof(temp_path) / sizeof(TCHAR),
1.336 + _T("%s\\steamapps\\%s"),
1.337 + steam_path,
1.338 + fd.cFileName);
1.339 +
1.340 + AddModsFromFolder(temp_path, SOURCE_ENGINE_UNKNOWN, db, gl);
1.341 +
1.342 + if (gl->game_count)
1.343 + {
1.344 + AttachGameListToGroup(&db->listen, gl);
1.345 + }
1.346 + else
1.347 + {
1.348 + free(gl);
1.349 + }
1.350 + }
1.351 + else
1.352 + {
1.353 + /* Look for listenserver games */
1.354 + game_list_t *gl = MakeGameList(fd.cFileName);
1.355 +
1.356 + for (unsigned int i = 0; valve_game_list[i].folder != NULL; i++)
1.357 + {
1.358 + unsigned int mod_id;
1.359 + UTIL_PathFormat(temp_path,
1.360 + sizeof(temp_path) / sizeof(TCHAR),
1.361 + _T("%s\\steamapps\\%s\\%s\\%s"),
1.362 + steam_path,
1.363 + fd.cFileName,
1.364 + valve_game_list[i].folder,
1.365 + valve_game_list[i].subfolder);
1.366 + if (TryToAddMod(temp_path, valve_game_list[i].eng_type, db, &mod_id))
1.367 + {
1.368 + AttachModToGameList(gl, mod_id);
1.369 + }
1.370 + }
1.371 +
1.372 + if (gl->game_count)
1.373 + {
1.374 + AttachGameListToGroup(&db->listen, gl);
1.375 + }
1.376 + else
1.377 + {
1.378 + free(gl);
1.379 + }
1.380 +
1.381 + /* Look for dedicated games */
1.382 + gl = MakeGameList(fd.cFileName);
1.383 +
1.384 + for (unsigned int i = 0; valve_server_list[i].folder != NULL; i++)
1.385 + {
1.386 + UTIL_PathFormat(temp_path,
1.387 + sizeof(temp_path) / sizeof(TCHAR),
1.388 + _T("%s\\steamapps\\%s\\%s"),
1.389 + steam_path,
1.390 + fd.cFileName,
1.391 + valve_server_list[i].folder);
1.392 + AddModsFromFolder(temp_path, valve_server_list[i].eng_type, db, gl);
1.393 + }
1.394 +
1.395 + if (gl->game_count)
1.396 + {
1.397 + AttachGameListToGroup(&db->dedicated, gl);
1.398 + }
1.399 + else
1.400 + {
1.401 + free(gl);
1.402 + }
1.403 + }
1.404 +
1.405 + } while (FindNextFile(hFind, &fd));
1.406 +
1.407 + FindClose(hFind);
1.408 + RegCloseKey(hkPath);
1.409 +}
1.410 +
1.411 +void GetStandaloneGames(game_database_t *db)
1.412 +{
1.413 + HKEY hkPath;
1.414 + DWORD dwLen, dwType, dwAttr;
1.415 + TCHAR temp_path[MAX_PATH];
1.416 + TCHAR hlds_path[MAX_PATH];
1.417 + game_list_t *games_standalone;
1.418 +
1.419 + if (RegOpenKeyEx(HKEY_CURRENT_USER,
1.420 + _T("Software\\Valve\\HLServer"),
1.421 + 0,
1.422 + KEY_READ,
1.423 + &hkPath) != ERROR_SUCCESS)
1.424 + {
1.425 + db->standalone.error_code = GAME_LIST_CANT_READ;
1.426 + return;
1.427 + }
1.428 +
1.429 + dwLen = sizeof(hlds_path) / sizeof(TCHAR);
1.430 + if (RegQueryValueEx(hkPath,
1.431 + _T("InstallPath"),
1.432 + NULL,
1.433 + &dwType,
1.434 + (LPBYTE)hlds_path,
1.435 + &dwLen) != ERROR_SUCCESS)
1.436 + {
1.437 + RegCloseKey(hkPath);
1.438 + db->standalone.error_code = GAME_LIST_CANT_READ;
1.439 + return;
1.440 + }
1.441 +
1.442 + /* Make sure there is a "srcds.exe" file */
1.443 + UTIL_PathFormat(temp_path,
1.444 + sizeof(temp_path) / sizeof(TCHAR),
1.445 + _T("%s\\srcds.exe"),
1.446 + hlds_path);
1.447 + dwAttr = GetFileAttributes(temp_path);
1.448 + if (dwAttr == INVALID_FILE_ATTRIBUTES)
1.449 + {
1.450 + db->standalone.error_code = GAME_LIST_HALFLIFE1;
1.451 + return;
1.452 + }
1.453 +
1.454 + games_standalone = MakeGameList(_T("Standalone"));
1.455 +
1.456 + /* If there is an "orangebox" sub folder, we can make a better guess
1.457 + * at the engine state.
1.458 + */
1.459 + UTIL_PathFormat(temp_path,
1.460 + sizeof(temp_path) / sizeof(TCHAR),
1.461 + _T("%s\\orangebox"),
1.462 + hlds_path);
1.463 + dwAttr = GetFileAttributes(temp_path);
1.464 + if (dwAttr != INVALID_FILE_ATTRIBUTES
1.465 + && ((dwAttr & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY))
1.466 + {
1.467 + AddModsFromFolder(temp_path, SOURCE_ENGINE_2007, db, games_standalone);
1.468 + }
1.469 +
1.470 + /* Add everything from the server */
1.471 + AddModsFromFolder(hlds_path, SOURCE_ENGINE_2004, db, games_standalone);
1.472 +
1.473 + if (games_standalone->game_count)
1.474 + {
1.475 + AttachGameListToGroup(&db->standalone, games_standalone);
1.476 + }
1.477 + else
1.478 + {
1.479 + free(games_standalone);
1.480 + }
1.481 +
1.482 + RegCloseKey(hkPath);
1.483 +}
1.484 +
1.485 +void DisplayBadGamesDialog(HWND hWnd, int reason)
1.486 +{
1.487 + TCHAR message[256];
1.488 + UINT idc = 0;
1.489 +
1.490 + if (reason == GAME_LIST_CANT_READ)
1.491 + {
1.492 + idc = IDS_GAME_FAIL_READ;
1.493 + }
1.494 + else if (reason == GAME_LIST_HALFLIFE1)
1.495 + {
1.496 + idc = IDS_GAME_FAIL_HL1;
1.497 + }
1.498 + else if (reason == GAME_LIST_NO_GAMES)
1.499 + {
1.500 + idc = IDS_GAME_FAIL_NONE;
1.501 + }
1.502 + else
1.503 + {
1.504 + return;
1.505 + }
1.506 +
1.507 + if (LoadString(g_hInstance,
1.508 + idc,
1.509 + message,
1.510 + sizeof(message) / sizeof(TCHAR)) == 0)
1.511 + {
1.512 + return;
1.513 + }
1.514 +
1.515 + MessageBox(hWnd,
1.516 + message,
1.517 + _T("SourceMod Installer"),
1.518 + MB_OK|MB_ICONWARNING);
1.519 +}
1.520 +
1.521 +int _ModIdCompare(const void *item1, const void *item2)
1.522 +{
1.523 + unsigned int mod_id1 = *(unsigned int *)item1;
1.524 + unsigned int mod_id2 = *(unsigned int *)item2;
1.525 +
1.526 + return tstrcasecmp(g_games.game_list[mod_id1].name, g_games.game_list[mod_id2].name);
1.527 +}
1.528 +
1.529 +int _GroupCompare(const void *item1, const void *item2)
1.530 +{
1.531 + game_list_t *g1 = *(game_list_t **)item1;
1.532 + game_list_t *g2 = *(game_list_t **)item2;
1.533 +
1.534 + return tstrcasecmp(g1->root_name, g2->root_name);
1.535 +}
1.536 +
1.537 +void SortGameGroup(game_group_t *group)
1.538 +{
1.539 + qsort(group->lists, group->list_count, sizeof(game_list_t *), _GroupCompare);
1.540 +
1.541 + for (unsigned int i = 0; i < group->list_count; i++)
1.542 + {
1.543 + qsort(group->lists[i]->games,
1.544 + group->lists[i]->game_count,
1.545 + sizeof(unsigned int),
1.546 + _ModIdCompare);
1.547 + }
1.548 +}
1.549 +
1.550 +void BuildGameDB()
1.551 +{
1.552 + ReleaseGameDB();
1.553 + GetStandaloneGames(&g_games);
1.554 + GetSteamGames(&g_games);
1.555 + SortGameGroup(&g_games.dedicated);
1.556 + SortGameGroup(&g_games.listen);
1.557 + SortGameGroup(&g_games.standalone);
1.558 +}
1.559 +
1.560 +void ReleaseGameGroup(game_group_t *group)
1.561 +{
1.562 + for (unsigned int i = 0; i < group->list_count; i++)
1.563 + {
1.564 + free(group->lists[i]->games);
1.565 + free(group->lists[i]);
1.566 + }
1.567 + free(group->lists);
1.568 +}
1.569 +
1.570 +void ReleaseGameDB()
1.571 +{
1.572 + ReleaseGameGroup(&g_games.dedicated);
1.573 + ReleaseGameGroup(&g_games.listen);
1.574 + ReleaseGameGroup(&g_games.standalone);
1.575 + free(g_games.game_list);
1.576 + memset(&g_games, 0, sizeof(g_games));
1.577 +}