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