sourcemod/tools/installer/GamesList.cpp
Scott Ehlert 251cced1f8 Spring Cleaning, Part Ichi (1)
Various minor things done to project files
Updated sample extension project file and updated makefile to the new unified version (more changes likely on the way)
Updated regex project file and makefile

--HG--
extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%401971
2008-03-30 07:00:22 +00:00

575 lines
12 KiB
C++

#include "GamesList.h"
#include "InstallerUtil.h"
#include "InstallerMain.h"
#include <stdio.h>
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));
}