dvander@1651: #include "GamesList.h" dvander@1651: #include "InstallerUtil.h" dvander@1651: #include "InstallerMain.h" dvander@1651: #include dvander@1651: dvander@1723: game_database_t g_games = dvander@1723: { dvander@1723: NULL, 0, dvander@1723: {NULL, 0, GAME_LIST_NO_GAMES}, dvander@1723: {NULL, 0, GAME_LIST_NO_GAMES}, dvander@1723: {NULL, 0, GAME_LIST_NO_GAMES} dvander@1723: }; dvander@1723: dvander@1723: valve_game_t valve_game_list[] = dvander@1723: { dvander@1723: {_T("counter-strike source"), _T("cstrike"), SOURCE_ENGINE_2004}, dvander@1723: {_T("day of defeat source"), _T("dod"), SOURCE_ENGINE_2004}, dvander@1723: {_T("half-life 2 deathmatch"), _T("hl2mp"), SOURCE_ENGINE_2004}, dvander@1723: {_T("half-life deathmatch source"), _T("hl1mp"), SOURCE_ENGINE_2004}, dvander@1723: {_T("team fortress 2"), _T("tf"), SOURCE_ENGINE_2007}, dvander@1723: {NULL, NULL, 0}, dvander@1723: }; dvander@1723: dvander@1723: valve_game_t valve_server_list[] = dvander@1723: { dvander@1723: {_T("source dedicated server"), NULL, SOURCE_ENGINE_2004}, dvander@1723: {_T("source 2007 dedicated server"), NULL, SOURCE_ENGINE_2007}, dvander@1723: {NULL, NULL, 0}, dvander@1723: }; dvander@1651: dvander@1651: int IsValidFolder(const TCHAR *path) dvander@1651: { dvander@1651: DWORD attr; dvander@1651: TCHAR gameinfo_file[MAX_PATH]; dvander@1651: dvander@1651: UTIL_PathFormat(gameinfo_file, sizeof(gameinfo_file), _T("%s\\gameinfo.txt"), path); dvander@1651: dvander@1651: if ((attr = GetFileAttributes(gameinfo_file)) == INVALID_FILE_ATTRIBUTES) dvander@1651: { dvander@1651: return GAMEINFO_DOES_NOT_EXIST; dvander@1651: } dvander@1651: dvander@1651: if ((attr & FILE_ATTRIBUTE_READONLY) == FILE_ATTRIBUTE_READONLY) dvander@1651: { dvander@1651: return GAMEINFO_IS_READ_ONLY; dvander@1651: } dvander@1651: dvander@1651: if ((attr & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY) dvander@1651: { dvander@1651: return GAMEINFO_DOES_NOT_EXIST; dvander@1651: } dvander@1651: dvander@1651: return GAMEINFO_IS_USABLE; dvander@1651: } dvander@1651: dvander@1651: void DisplayBadFolderDialog(HWND hDlg, int reason) dvander@1651: { dvander@1651: TCHAR message_string[255]; dvander@1651: UINT resource; dvander@1651: dvander@1651: if (reason == GAMEINFO_DOES_NOT_EXIST) dvander@1651: { dvander@1651: resource = IDS_NO_GAMEINFO; dvander@1651: } dvander@1651: else if (reason == GAMEINFO_IS_READ_ONLY) dvander@1651: { dvander@1651: resource = IDS_READONLY_GAMEINFO; dvander@1651: } dvander@1651: else dvander@1651: { dvander@1651: return; dvander@1651: } dvander@1651: dvander@1651: if (LoadString(g_hInstance, dvander@1651: resource, dvander@1651: message_string, dvander@1651: sizeof(message_string) / sizeof(TCHAR) dvander@1651: ) == 0) dvander@1651: { dvander@1651: return; dvander@1651: } dvander@1651: dvander@1651: MessageBox(hDlg, dvander@1651: message_string, dvander@1651: _T("SourceMod Installer"), dvander@1651: MB_OK|MB_ICONWARNING); dvander@1651: } dvander@1651: dvander@1723: game_list_t *MakeGameList(const TCHAR *name) dvander@1651: { dvander@1723: game_list_t *gl = (game_list_t *)malloc(sizeof(game_list_t)); dvander@1723: dvander@1723: UTIL_Format(gl->root_name, dvander@1723: sizeof(gl->root_name) / sizeof(TCHAR), dvander@1723: _T("%s"), dvander@1723: name); dvander@1723: gl->game_count = 0; dvander@1723: gl->games = NULL; dvander@1651: dvander@1723: return gl; dvander@1723: } dvander@1723: dvander@1723: void AttachGameListToGroup(game_group_t *group, game_list_t *gl) dvander@1723: { dvander@1723: if (group->lists == NULL) dvander@1651: { dvander@1723: group->lists = (game_list_t **)malloc(sizeof(game_list_t *)); dvander@1651: } dvander@1651: else dvander@1651: { dvander@1723: group->lists = (game_list_t **)realloc(group->lists, dvander@1723: sizeof(game_list_t *) * (group->list_count + 1)); dvander@1723: } dvander@1723: dvander@1723: group->lists[group->list_count] = gl; dvander@1723: group->list_count++; dvander@1723: } dvander@1723: dvander@1723: void AttachModToGameList(game_list_t *gl, unsigned int mod_id) dvander@1723: { dvander@1723: if (gl->games == NULL) dvander@1723: { dvander@1723: gl->games = (unsigned int *)malloc(sizeof(unsigned int)); dvander@1723: } dvander@1723: else dvander@1723: { dvander@1723: gl->games = (unsigned int *)realloc(gl->games, dvander@1723: sizeof(unsigned int) * (gl->game_count + 1)); dvander@1651: } dvander@1651: dvander@1723: gl->games[gl->game_count] = mod_id; dvander@1723: gl->game_count++; dvander@1651: } dvander@1651: dvander@1723: unsigned int AddModToList(game_database_t *db, const game_info_t *mod_info) dvander@1723: { dvander@1723: /* Check if a matching game already exists */ dvander@1723: for (unsigned int i = 0; i < db->game_count; i++) dvander@1723: { dvander@1723: if (tstrcasecmp(mod_info->game_path, db->game_list[i].game_path) == 0) dvander@1723: { dvander@1723: return i; dvander@1723: } dvander@1723: } dvander@1723: dvander@1723: if (db->game_list == NULL) dvander@1723: { dvander@1723: db->game_list = (game_info_t *)malloc(sizeof(game_info_t)); dvander@1723: } dvander@1723: else dvander@1723: { dvander@1723: db->game_list = (game_info_t *)realloc(db->game_list, dvander@1723: sizeof(game_info_t) * (db->game_count + 1)); dvander@1723: } dvander@1723: dvander@1723: memcpy(&db->game_list[db->game_count], mod_info, sizeof(game_info_t)); dvander@1723: db->game_count++; dvander@1723: dvander@1723: return db->game_count - 1; dvander@1723: } dvander@1723: dvander@1723: bool TryToAddMod(const TCHAR *path, int eng_type, game_database_t *db, unsigned int *id) dvander@1651: { dvander@1651: FILE *fp; dvander@1651: TCHAR gameinfo_path[MAX_PATH]; dvander@1651: dvander@1651: UTIL_PathFormat(gameinfo_path, dvander@1651: sizeof(gameinfo_path), dvander@1651: _T("%s\\gameinfo.txt"), dvander@1651: path); dvander@1651: dvander@1651: if ((fp = _tfopen(gameinfo_path, _T("rt"))) == NULL) dvander@1651: { dvander@1723: return false; dvander@1651: } dvander@1651: dvander@1651: int pos; dvander@1651: char buffer[512]; dvander@1651: char key[256], value[256]; dvander@1651: while (!feof(fp) && fgets(buffer, sizeof(buffer), fp) != NULL) dvander@1651: { dvander@1651: if ((pos = BreakStringA(buffer, key, sizeof(key))) == -1) dvander@1651: { dvander@1651: continue; dvander@1651: } dvander@1651: if ((pos = BreakStringA(&buffer[pos], value, sizeof(value))) == -1) dvander@1651: { dvander@1651: continue; dvander@1651: } dvander@1651: if (strcmp(key, "game") == 0) dvander@1651: { dvander@1723: game_info_t mod; dvander@1723: unsigned int got_id; dvander@1723: dvander@1651: AnsiToUnicode(value, mod.name, sizeof(mod.name)); dvander@1723: UTIL_Format(mod.game_path, sizeof(mod.game_path), _T("%s"), path); dvander@1651: mod.source_engine = eng_type; dvander@1723: dvander@1723: got_id = AddModToList(db, &mod); dvander@1723: dvander@1723: if (id != NULL) dvander@1723: { dvander@1723: *id = got_id; dvander@1723: } dvander@1723: dvander@1723: fclose(fp); dvander@1723: dvander@1723: return true; dvander@1651: } dvander@1651: } dvander@1651: dvander@1651: fclose(fp); dvander@1723: dvander@1723: return false; dvander@1651: } dvander@1651: dvander@1723: void AddModsFromFolder(const TCHAR *path, dvander@1723: int eng_type, dvander@1723: game_database_t *db, dvander@1723: game_list_t *gl) dvander@1651: { dvander@1651: HANDLE hFind; dvander@1651: WIN32_FIND_DATA fd; dvander@1651: TCHAR temp_path[MAX_PATH]; dvander@1651: TCHAR search_path[MAX_PATH]; dvander@1723: unsigned int mod_id; dvander@1651: dvander@1651: UTIL_Format(search_path, dvander@1651: sizeof(search_path), dvander@1651: _T("%s\\*.*"), dvander@1651: path); dvander@1651: dvander@1651: if ((hFind = FindFirstFile(search_path, &fd)) == INVALID_HANDLE_VALUE) dvander@1651: { dvander@1651: return; dvander@1651: } dvander@1651: dvander@1651: do dvander@1651: { dvander@1651: if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY) dvander@1651: { dvander@1651: continue; dvander@1651: } dvander@1651: dvander@1651: if (tstrcasecmp(fd.cFileName, _T(".")) == 0 dvander@1651: || tstrcasecmp(fd.cFileName, _T("..")) == 0) dvander@1651: { dvander@1651: continue; dvander@1651: } dvander@1651: dvander@1651: UTIL_PathFormat(temp_path, dvander@1651: sizeof(temp_path), dvander@1651: _T("%s\\%s"), dvander@1651: path, dvander@1651: fd.cFileName); dvander@1723: if (TryToAddMod(temp_path, eng_type, db, &mod_id)) dvander@1723: { dvander@1723: AttachModToGameList(gl, mod_id); dvander@1723: } dvander@1651: } while (FindNextFile(hFind, &fd)); dvander@1651: dvander@1651: FindClose(hFind); dvander@1651: } dvander@1651: dvander@1723: void GetSteamGames(game_database_t *db) dvander@1651: { dvander@1723: HKEY hkPath; dvander@1723: DWORD dwLen, dwType; dvander@1651: HANDLE hFind; dvander@1651: WIN32_FIND_DATA fd; dvander@1651: TCHAR temp_path[MAX_PATH]; dvander@1723: TCHAR steam_path[MAX_PATH]; dvander@1723: TCHAR steamapps_path[MAX_PATH]; dvander@1723: dvander@1723: if (RegOpenKeyEx(HKEY_CURRENT_USER, dvander@1723: _T("Software\\Valve\\Steam"), dvander@1723: 0, dvander@1723: KEY_READ, dvander@1723: &hkPath) != ERROR_SUCCESS) dvander@1723: { dvander@1723: db->listen.error_code = GAME_LIST_CANT_READ; dvander@1723: db->dedicated.error_code = GAME_LIST_CANT_READ; dvander@1723: return; dvander@1723: } dvander@1651: dvander@1723: dwLen = sizeof(steam_path) / sizeof(TCHAR); dvander@1723: if (RegQueryValueEx(hkPath, dvander@1723: _T("SteamPath"), dvander@1723: NULL, dvander@1723: &dwType, dvander@1723: (LPBYTE)steam_path, dvander@1723: &dwLen) != ERROR_SUCCESS) dvander@1723: { dvander@1723: RegCloseKey(hkPath); dvander@1723: db->listen.error_code = GAME_LIST_CANT_READ; dvander@1723: db->dedicated.error_code = GAME_LIST_CANT_READ; dvander@1723: return; dvander@1723: } dvander@1651: dvander@1723: UTIL_PathFormat(steamapps_path, dvander@1723: sizeof(steamapps_path) / sizeof(TCHAR), dvander@1723: _T("%s\\steamapps\\*.*"), dvander@1723: steam_path); dvander@1723: dvander@1723: if ((hFind = FindFirstFile(steamapps_path, &fd)) == INVALID_HANDLE_VALUE) dvander@1651: { dvander@1723: RegCloseKey(hkPath); dvander@1723: db->listen.error_code = GAME_LIST_CANT_READ; dvander@1723: db->dedicated.error_code = GAME_LIST_CANT_READ; dvander@1651: return; dvander@1651: } dvander@1651: dvander@1651: do dvander@1651: { dvander@1651: if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY) dvander@1651: { dvander@1651: continue; dvander@1651: } dvander@1651: dvander@1651: if (tstrcasecmp(fd.cFileName, _T(".")) == 0 dvander@1651: || tstrcasecmp(fd.cFileName, _T("..")) == 0) dvander@1651: { dvander@1651: continue; dvander@1651: } dvander@1651: dvander@1723: /* If we get a folder called "SourceMods," look for third party mods */ dvander@1723: if (tstrcasecmp(fd.cFileName, _T("SourceMods")) == 0) dvander@1651: { dvander@1723: game_list_t *gl = MakeGameList(_T("Third-Party Games")); dvander@1723: dvander@1723: UTIL_PathFormat(temp_path, dvander@1723: sizeof(temp_path) / sizeof(TCHAR), dvander@1723: _T("%s\\steamapps\\%s"), dvander@1723: steam_path, dvander@1723: fd.cFileName); dvander@1723: dvander@1723: AddModsFromFolder(temp_path, SOURCE_ENGINE_UNKNOWN, db, gl); dvander@1723: dvander@1723: if (gl->game_count) dvander@1651: { dvander@1723: AttachGameListToGroup(&db->listen, gl); dvander@1651: } dvander@1723: else dvander@1651: { dvander@1723: free(gl); dvander@1651: } dvander@1651: } dvander@1723: else dvander@1651: { dvander@1723: /* Look for listenserver games */ dvander@1723: game_list_t *gl = MakeGameList(fd.cFileName); dvander@1723: dvander@1723: for (unsigned int i = 0; valve_game_list[i].folder != NULL; i++) dvander@1723: { dvander@1723: unsigned int mod_id; dvander@1723: UTIL_PathFormat(temp_path, dvander@1723: sizeof(temp_path) / sizeof(TCHAR), dvander@1723: _T("%s\\steamapps\\%s\\%s\\%s"), dvander@1723: steam_path, dvander@1723: fd.cFileName, dvander@1723: valve_game_list[i].folder, dvander@1723: valve_game_list[i].subfolder); dvander@1723: if (TryToAddMod(temp_path, valve_game_list[i].eng_type, db, &mod_id)) dvander@1723: { dvander@1723: AttachModToGameList(gl, mod_id); dvander@1723: } dvander@1723: } dvander@1723: dvander@1723: if (gl->game_count) dvander@1723: { dvander@1723: AttachGameListToGroup(&db->listen, gl); dvander@1723: } dvander@1723: else dvander@1723: { dvander@1723: free(gl); dvander@1723: } dvander@1723: dvander@1723: /* Look for dedicated games */ dvander@1723: gl = MakeGameList(fd.cFileName); dvander@1723: dvander@1723: for (unsigned int i = 0; valve_server_list[i].folder != NULL; i++) dvander@1651: { dvander@1651: UTIL_PathFormat(temp_path, dvander@1651: sizeof(temp_path) / sizeof(TCHAR), dvander@1723: _T("%s\\steamapps\\%s\\%s"), dvander@1723: steam_path, dvander@1723: fd.cFileName, dvander@1723: valve_server_list[i].folder); dvander@1723: AddModsFromFolder(temp_path, valve_server_list[i].eng_type, db, gl); dvander@1651: } dvander@1723: dvander@1723: if (gl->game_count) dvander@1651: { dvander@1723: AttachGameListToGroup(&db->dedicated, gl); dvander@1651: } dvander@1723: else dvander@1723: { dvander@1723: free(gl); dvander@1723: } dvander@1651: } dvander@1651: dvander@1651: } while (FindNextFile(hFind, &fd)); dvander@1651: dvander@1651: FindClose(hFind); dvander@1723: RegCloseKey(hkPath); dvander@1651: } dvander@1651: dvander@1723: void GetStandaloneGames(game_database_t *db) dvander@1651: { dvander@1723: HKEY hkPath; dvander@1723: DWORD dwLen, dwType, dwAttr; dvander@1723: TCHAR temp_path[MAX_PATH]; dvander@1723: TCHAR hlds_path[MAX_PATH]; dvander@1723: game_list_t *games_standalone; dvander@1651: dvander@1723: if (RegOpenKeyEx(HKEY_CURRENT_USER, dvander@1723: _T("Software\\Valve\\HLServer"), dvander@1723: 0, dvander@1723: KEY_READ, dvander@1723: &hkPath) != ERROR_SUCCESS) dvander@1651: { dvander@1723: db->standalone.error_code = GAME_LIST_CANT_READ; dvander@1723: return; dvander@1651: } dvander@1651: dvander@1723: dwLen = sizeof(hlds_path) / sizeof(TCHAR); dvander@1723: if (RegQueryValueEx(hkPath, dvander@1723: _T("InstallPath"), dvander@1723: NULL, dvander@1723: &dwType, dvander@1723: (LPBYTE)hlds_path, dvander@1723: &dwLen) != ERROR_SUCCESS) dvander@1651: { dvander@1723: RegCloseKey(hkPath); dvander@1723: db->standalone.error_code = GAME_LIST_CANT_READ; dvander@1651: return; dvander@1651: } dvander@1651: dvander@1723: /* Make sure there is a "srcds.exe" file */ dvander@1723: UTIL_PathFormat(temp_path, dvander@1723: sizeof(temp_path) / sizeof(TCHAR), dvander@1723: _T("%s\\srcds.exe"), dvander@1723: hlds_path); dvander@1723: dwAttr = GetFileAttributes(temp_path); dvander@1723: if (dwAttr == INVALID_FILE_ATTRIBUTES) dvander@1723: { dvander@1723: db->standalone.error_code = GAME_LIST_HALFLIFE1; dvander@1723: return; dvander@1723: } dvander@1723: dvander@1723: games_standalone = MakeGameList(_T("Standalone")); dvander@1723: dvander@1723: /* If there is an "orangebox" sub folder, we can make a better guess dvander@1723: * at the engine state. dvander@1723: */ dvander@1723: UTIL_PathFormat(temp_path, dvander@1723: sizeof(temp_path) / sizeof(TCHAR), dvander@1723: _T("%s\\orangebox"), dvander@1723: hlds_path); dvander@1723: dwAttr = GetFileAttributes(temp_path); dvander@1723: if (dwAttr != INVALID_FILE_ATTRIBUTES dvander@1723: && ((dwAttr & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)) dvander@1723: { dvander@1723: AddModsFromFolder(temp_path, SOURCE_ENGINE_2007, db, games_standalone); dvander@1723: } dvander@1723: dvander@1723: /* Add everything from the server */ dvander@1723: AddModsFromFolder(hlds_path, SOURCE_ENGINE_2004, db, games_standalone); dvander@1723: dvander@1723: if (games_standalone->game_count) dvander@1723: { dvander@1723: AttachGameListToGroup(&db->standalone, games_standalone); dvander@1723: } dvander@1723: else dvander@1723: { dvander@1723: free(games_standalone); dvander@1723: } dvander@1723: dvander@1723: RegCloseKey(hkPath); dvander@1651: } dvander@1651: dvander@1723: void DisplayBadGamesDialog(HWND hWnd, int reason) dvander@1651: { dvander@1651: TCHAR message[256]; dvander@1651: UINT idc = 0; dvander@1651: dvander@1651: if (reason == GAME_LIST_CANT_READ) dvander@1651: { dvander@1651: idc = IDS_GAME_FAIL_READ; dvander@1651: } dvander@1651: else if (reason == GAME_LIST_HALFLIFE1) dvander@1651: { dvander@1651: idc = IDS_GAME_FAIL_HL1; dvander@1651: } dvander@1651: else if (reason == GAME_LIST_NO_GAMES) dvander@1651: { dvander@1651: idc = IDS_GAME_FAIL_NONE; dvander@1651: } dvander@1651: else dvander@1651: { dvander@1651: return; dvander@1651: } dvander@1651: dvander@1651: if (LoadString(g_hInstance, dvander@1651: idc, dvander@1651: message, dvander@1651: sizeof(message) / sizeof(TCHAR)) == 0) dvander@1651: { dvander@1651: return; dvander@1651: } dvander@1651: dvander@1651: MessageBox(hWnd, dvander@1651: message, dvander@1651: _T("SourceMod Installer"), dvander@1651: MB_OK|MB_ICONWARNING); dvander@1651: } dvander@1723: dvander@1723: int _ModIdCompare(const void *item1, const void *item2) dvander@1723: { dvander@1723: unsigned int mod_id1 = *(unsigned int *)item1; dvander@1723: unsigned int mod_id2 = *(unsigned int *)item2; dvander@1723: dvander@1723: return tstrcasecmp(g_games.game_list[mod_id1].name, g_games.game_list[mod_id2].name); dvander@1723: } dvander@1723: dvander@1723: int _GroupCompare(const void *item1, const void *item2) dvander@1723: { dvander@1723: game_list_t *g1 = *(game_list_t **)item1; dvander@1723: game_list_t *g2 = *(game_list_t **)item2; dvander@1723: dvander@1723: return tstrcasecmp(g1->root_name, g2->root_name); dvander@1723: } dvander@1723: dvander@1723: void SortGameGroup(game_group_t *group) dvander@1723: { dvander@1723: qsort(group->lists, group->list_count, sizeof(game_list_t *), _GroupCompare); dvander@1723: dvander@1723: for (unsigned int i = 0; i < group->list_count; i++) dvander@1723: { dvander@1723: qsort(group->lists[i]->games, dvander@1723: group->lists[i]->game_count, dvander@1723: sizeof(unsigned int), dvander@1723: _ModIdCompare); dvander@1723: } dvander@1723: } dvander@1723: dvander@1723: void BuildGameDB() dvander@1723: { dvander@1723: ReleaseGameDB(); dvander@1723: GetStandaloneGames(&g_games); dvander@1723: GetSteamGames(&g_games); dvander@1723: SortGameGroup(&g_games.dedicated); dvander@1723: SortGameGroup(&g_games.listen); dvander@1723: SortGameGroup(&g_games.standalone); dvander@1723: } dvander@1723: dvander@1723: void ReleaseGameGroup(game_group_t *group) dvander@1723: { dvander@1723: for (unsigned int i = 0; i < group->list_count; i++) dvander@1723: { dvander@1723: free(group->lists[i]->games); dvander@1723: free(group->lists[i]); dvander@1723: } dvander@1723: free(group->lists); dvander@1723: } dvander@1723: dvander@1723: void ReleaseGameDB() dvander@1723: { dvander@1723: ReleaseGameGroup(&g_games.dedicated); dvander@1723: ReleaseGameGroup(&g_games.listen); dvander@1723: ReleaseGameGroup(&g_games.standalone); dvander@1723: free(g_games.game_list); dvander@1723: memset(&g_games, 0, sizeof(g_games)); dvander@1723: }