Menu-FN/Platform: Move all the custom game parsing/install code into platform/, also clean up a bunch of routines in there
This commit is contained in:
parent
050db32a81
commit
2576f803cd
9 changed files with 684 additions and 792 deletions
|
@ -132,7 +132,7 @@ m_init(void)
|
|||
g_btnsize = drawgetimagesize(g_bmp[BTNS_MAIN]);
|
||||
g_btnofs = 26 / g_btnsize[1];
|
||||
|
||||
games_init();
|
||||
GameLibrary_Init();
|
||||
main_init();
|
||||
|
||||
Colors_Init();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2016-2022 Vera Visions LLC.
|
||||
* Copyright (c) 2016-2023 Vera Visions LLC.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -29,657 +29,37 @@ CMainButton customgame_btnRefresh;
|
|||
CMainButton customgame_btnDeactivate;
|
||||
CMainButton customgame_btnDone;
|
||||
|
||||
int g_iModInstallCache;
|
||||
string g_strModInstallCache;
|
||||
|
||||
/* get installing id */
|
||||
void
|
||||
game_getinstallcache(void)
|
||||
{
|
||||
int ret;
|
||||
filestream fs_cache;
|
||||
|
||||
ret = 0;
|
||||
fs_cache = fopen("mcache.dat", FILE_READ);
|
||||
|
||||
if (fs_cache >= 0) {
|
||||
g_iModInstallCache = (int)stof(fgets(fs_cache));
|
||||
g_strModInstallCache = fgets(fs_cache);
|
||||
fclose(fs_cache);
|
||||
} else {
|
||||
g_iModInstallCache = -1;
|
||||
g_strModInstallCache = "";
|
||||
}
|
||||
|
||||
print(sprintf("id: %i, name: %s\n", ret, g_strModInstallCache));
|
||||
}
|
||||
|
||||
/* write installing id */
|
||||
void
|
||||
game_writeinstallcache(int id, string gamedir)
|
||||
{
|
||||
filestream fs_cache;
|
||||
|
||||
fs_cache = fopen("mcache.dat", FILE_WRITE);
|
||||
g_iModInstallCache = id;
|
||||
g_strModInstallCache = gamedir;
|
||||
|
||||
if (fs_cache >= 0) {
|
||||
fputs(fs_cache, sprintf("%i\n",id));
|
||||
fputs(fs_cache, gamedir);
|
||||
fclose(fs_cache);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
game_getpackageid(string pkgname)
|
||||
{
|
||||
string f;
|
||||
|
||||
for (int i = 0; (getpackagemanagerinfo(i, GPMI_NAME)); i++) {
|
||||
string name;
|
||||
name = getpackagemanagerinfo(i, GPMI_NAME);
|
||||
|
||||
/* Spike started randomly putting version numbers into package names */
|
||||
f = sprintf("%s=%s", pkgname, getpackagemanagerinfo(i, GPMI_VERSION));
|
||||
|
||||
if (name == f) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
/* no package id whatsoever */
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* return 1 if any of the packages are pending, installing, or corrupt */
|
||||
int
|
||||
game_updatesavailable(void)
|
||||
{
|
||||
/* look for the valid packages in the gameinfo pkgname */
|
||||
int pkgcount = tokenize(games[gameinfo_current].pkgname);
|
||||
|
||||
for (int i = 0i; i < pkgcount; i++) {
|
||||
int id = game_getpackageid(argv(i));
|
||||
string status = getpackagemanagerinfo(id, GPMI_INSTALLED);
|
||||
|
||||
if (id == -1)
|
||||
continue;
|
||||
|
||||
switch (status) {
|
||||
case "":
|
||||
if (updates[id].installed == "") {
|
||||
return (1);
|
||||
} else if (updates[id].installed == "pending") {
|
||||
return (1);
|
||||
}
|
||||
break;
|
||||
case "pending":
|
||||
return (1);
|
||||
break;
|
||||
case "enabled":
|
||||
break;
|
||||
case "present":
|
||||
return (1);
|
||||
break;
|
||||
case "corrupt":
|
||||
return (1);
|
||||
break;
|
||||
default:
|
||||
/* we're currently installing stuff */
|
||||
return (1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* everything is installed */
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
game_updateinstallcount(void)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
/* always return something positive when no packages are defined */
|
||||
if (games[gameinfo_current].pkgname == "") {
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* look for the valid packages in the gameinfo pkgname */
|
||||
int pkgcount = tokenize(games[gameinfo_current].pkgname);
|
||||
|
||||
for (int i = 0i; i < pkgcount; i++) {
|
||||
int id = game_getpackageid(argv(i));
|
||||
string status = getpackagemanagerinfo(id, GPMI_INSTALLED);
|
||||
|
||||
switch (status) {
|
||||
case "":
|
||||
break;
|
||||
case "pending":
|
||||
break;
|
||||
case "enabled":
|
||||
count++;
|
||||
break;
|
||||
case "present":
|
||||
count++;
|
||||
break;
|
||||
case "corrupt":
|
||||
count++;
|
||||
break;
|
||||
default:
|
||||
/* we're currently installing stuff */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* everything is installed */
|
||||
return count;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* local game/mod info parsing */
|
||||
void
|
||||
games_set(int id)
|
||||
{
|
||||
gameinfo_current = id;
|
||||
setwindowcaption(games[id].game);
|
||||
cvar_set("com_fullgamename", games[id].game);
|
||||
}
|
||||
|
||||
#ifndef WEBMENU
|
||||
void
|
||||
customgame_liblist_parse(int id, string strKey, string strValue)
|
||||
{
|
||||
switch(strKey) {
|
||||
case "game":
|
||||
games[id].game = strValue;
|
||||
break;
|
||||
case "gamedir":
|
||||
games[id].gamedir = strValue;
|
||||
break;
|
||||
case "fallback_dir":
|
||||
games[id].fallback_dir = strValue;
|
||||
break;
|
||||
case "url_info":
|
||||
games[id].url_info = strValue;
|
||||
break;
|
||||
case "url_dl":
|
||||
games[id].url_dl = strValue;
|
||||
break;
|
||||
case "version":
|
||||
games[id].version = strValue;
|
||||
break;
|
||||
case "size":
|
||||
games[id].size = (int)stof(strValue);
|
||||
break;
|
||||
case "svonly":
|
||||
games[id].svonly = (int)stof(strValue);
|
||||
break;
|
||||
case "cldll":
|
||||
games[id].cldll = (int)stof(strValue);
|
||||
break;
|
||||
case "type":
|
||||
switch (strtolower(strValue)) {
|
||||
case "multiplayer_only":
|
||||
case "multiplayer only":
|
||||
games[id].type = "Multiplayer";
|
||||
break;
|
||||
case "singleplayer_only":
|
||||
case "singleplayer only":
|
||||
games[id].type = "Singleplayer";
|
||||
break;
|
||||
/* this... kind of sucks, but some games (gearbox) never updated
|
||||
* their liblist to reflect that they do multiplayer */
|
||||
case "sp":
|
||||
case "single":
|
||||
case "singleplayer":
|
||||
case "mp":
|
||||
case "multi":
|
||||
case "multiplayer":
|
||||
default:
|
||||
games[id].type = "Both";
|
||||
}
|
||||
break;
|
||||
case "minversion":
|
||||
case "hlversion":
|
||||
games[id].hlversion = strValue;
|
||||
break;
|
||||
case "nomodels":
|
||||
games[id].nomodels = (int)stof(strValue);
|
||||
break;
|
||||
case "nosprays":
|
||||
games[id].nosprays = (int)stof(strValue);
|
||||
break;
|
||||
case "mpentity":
|
||||
games[id].mpentity = strValue;
|
||||
break;
|
||||
case "gamedll":
|
||||
games[id].gamedll = strValue;
|
||||
break;
|
||||
case "startmap":
|
||||
games[id].startmap = strcat("map ", strValue, "\n");
|
||||
break;
|
||||
case "trainingmap":
|
||||
games[id].trainingmap = strcat("map ", strValue, "\n");
|
||||
break;
|
||||
/* newly added with Nuclide */
|
||||
case "pkgname":
|
||||
games[id].pkgname = strValue;
|
||||
games[id].pkgid = game_getpackageid(games[id].pkgname);
|
||||
break;
|
||||
case "pkgfile":
|
||||
games[id].pkgfile = strValue;
|
||||
break;
|
||||
case "chatroom":
|
||||
games[id].chatroom = strValue;
|
||||
break;
|
||||
case "readme":
|
||||
games[id].readme = strValue;
|
||||
break;
|
||||
case "menumap":
|
||||
games[id].menumap = strValue;
|
||||
break;
|
||||
case "introvideo":
|
||||
games[id].introvideo = strValue;
|
||||
break;
|
||||
case "steambg":
|
||||
games[id].steambg = (int)stof(strValue);
|
||||
break;
|
||||
case "base_dir":
|
||||
games[id].base_dir = strValue;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* looks for a single find inside a gamedir, including its pk3s and returns
|
||||
* a valid filehandle if it is found */
|
||||
filestream
|
||||
games_find_in_gamedir(string filename, string gamedirname)
|
||||
{
|
||||
searchhandle sh;
|
||||
searchhandle gsh;
|
||||
searchhandle psh;
|
||||
filestream fh;
|
||||
|
||||
/* first let's see if we've got a liblist.gam just floating inside the gamedir */
|
||||
gsh = search_begin(filename, SB_FULLPACKAGEPATH | SB_FORCESEARCH | SEARCH_ALLOWDUPES, FALSE, gamedirname);
|
||||
fh = search_fopen(gsh, 0);
|
||||
|
||||
/* we do not. let's search for pk3's to sift through */
|
||||
if (fh < 0) {
|
||||
/* let's search for every pk3 in the gamedir and search for a liblist, one at a time. */
|
||||
psh = search_begin("*.pk3", SB_FULLPACKAGEPATH | SB_FORCESEARCH, FALSE, gamedirname);
|
||||
|
||||
/* loop through each pk3 in reverse (newest to old) */
|
||||
for (int i = search_getsize(psh); i >= 0; i--) {
|
||||
string full = search_getfilename(psh, i);
|
||||
|
||||
if (!full)
|
||||
continue;
|
||||
|
||||
sh = search_begin(filename, SB_FULLPACKAGEPATH | SB_FORCESEARCH, FALSE, strcat(gamedirname, "/", full));
|
||||
fh = search_fopen(sh, 0);
|
||||
//print(sprintf("looking for %s in %s\n", filename, strcat(gamedirname, "/", full)));
|
||||
|
||||
/* we found one */
|
||||
if (fh >= 0) {
|
||||
search_end(sh);
|
||||
break;
|
||||
}
|
||||
search_end(sh);
|
||||
}
|
||||
search_end(psh);
|
||||
}
|
||||
|
||||
/* we do not. let's search for pk3's to sift through */
|
||||
if (fh < 0) {
|
||||
/* let's search for every pk3 in the gamedir and search for a liblist, one at a time. */
|
||||
psh = search_begin("dlcache/*.pk3.*", SB_FULLPACKAGEPATH | SB_FORCESEARCH | SEARCH_ALLOWDUPES, FALSE, gamedirname);
|
||||
|
||||
/* loop through each pk3 in reverse (newest to old) */
|
||||
for (int i = search_getsize(psh); i >= 0; i--) {
|
||||
string full = search_getfilename(psh, i);
|
||||
//print(sprintf("%s\n", full));
|
||||
|
||||
if (!full)
|
||||
continue;
|
||||
|
||||
sh = search_begin(filename, SB_FULLPACKAGEPATH | SB_FORCESEARCH | SEARCH_ALLOWDUPES, FALSE, strcat(gamedirname, "/", full));
|
||||
fh = search_fopen(sh, 0);
|
||||
//print(sprintf("looking for %s in %s\n", filename, strcat(gamedirname, "/", full)));
|
||||
|
||||
/* we found one */
|
||||
if (fh >= 0) {
|
||||
search_end(sh);
|
||||
break;
|
||||
}
|
||||
search_end(sh);
|
||||
}
|
||||
search_end(psh);
|
||||
}
|
||||
|
||||
/* still nothing. let's search for pk4's to sift through */
|
||||
if (fh < 0) {
|
||||
/* let's search for every pk4 in the gamedir and search for a liblist, one at a time. */
|
||||
psh = search_begin("*.pk4", SB_FULLPACKAGEPATH | SB_FORCESEARCH | SEARCH_ALLOWDUPES, FALSE, gamedirname);
|
||||
|
||||
/* loop through each pk4 in reverse (newest to old) */
|
||||
for (int i = search_getsize(psh); i >= 0; i--) {
|
||||
string full = search_getfilename(psh, i);
|
||||
|
||||
if (!full)
|
||||
continue;
|
||||
|
||||
sh = search_begin(filename, SB_FULLPACKAGEPATH | SB_FORCESEARCH | SEARCH_ALLOWDUPES, FALSE, strcat(gamedirname, "/", full));
|
||||
fh = search_fopen(sh, 0);
|
||||
|
||||
/* we found one */
|
||||
if (fh >= 0) {
|
||||
search_end(sh);
|
||||
break;
|
||||
}
|
||||
search_end(sh);
|
||||
}
|
||||
search_end(psh);
|
||||
}
|
||||
|
||||
search_end(gsh);
|
||||
return (fh);
|
||||
}
|
||||
|
||||
/* check if a gameinfo.txt for the gamedir contains gameinfo, parse it if present */
|
||||
int
|
||||
games_check_gtxt(int id, string gamedirname)
|
||||
{
|
||||
string temp;
|
||||
filestream fh;
|
||||
int ret = 0;
|
||||
|
||||
fh = games_find_in_gamedir("gameinfo.txt", gamedirname);
|
||||
|
||||
if (fh < 0)
|
||||
fh = games_find_in_gamedir("GameInfo.txt", gamedirname);
|
||||
|
||||
/* we have found a liblist.gam */
|
||||
if (fh >= 0) {
|
||||
string gamedirchain = "";
|
||||
int braced = 0;
|
||||
|
||||
while ((temp = fgets(fh))) {
|
||||
string token;
|
||||
tokenize_console(temp);
|
||||
token = strtolower(argv(0));
|
||||
|
||||
if (!token)
|
||||
continue;
|
||||
|
||||
if (token == "{")
|
||||
braced++;
|
||||
|
||||
if (token == "}")
|
||||
braced--;
|
||||
|
||||
if (braced == 1) {
|
||||
/* GameInfo */
|
||||
switch (token) {
|
||||
case "game":
|
||||
games[id].game = argv(1);
|
||||
break;
|
||||
case "type":
|
||||
games[id].type = argv(1);
|
||||
break;
|
||||
}
|
||||
} else if (braced == 2) {
|
||||
/* FileSystem */
|
||||
switch (token) {
|
||||
case "steamappid":
|
||||
break;
|
||||
case "toolsappid":
|
||||
break;
|
||||
}
|
||||
} else if (braced == 3) {
|
||||
/* SearchPaths */
|
||||
switch (token) {
|
||||
case "game":
|
||||
if (argv(1) == "|gameinfo_path|.")
|
||||
gamedirchain = strcat(gamedirchain, games[id].gamedir, " ");
|
||||
else
|
||||
gamedirchain = strcat(gamedirchain, argv(1), " ");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* in gameinfo.txt files, we list game load-order in reverse */
|
||||
if (gamedirchain) {
|
||||
string maindir = games[id].gamedir;
|
||||
float c = tokenize(gamedirchain);
|
||||
|
||||
for (float i = c-1; i >= 0; i--) {
|
||||
if (argv(i) == maindir)
|
||||
continue;
|
||||
|
||||
if (i == 0)
|
||||
games[id].gamedir = strcat(games[id].gamedir, argv(i));
|
||||
else
|
||||
games[id].gamedir = strcat(games[id].gamedir, argv(i), ";");
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fh);
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/* check if a manifest for the gamedir contains gameinfo, parse it if present */
|
||||
int
|
||||
games_check_manifest(int id, string gamedirname)
|
||||
{
|
||||
int ret = 0;
|
||||
float count;
|
||||
|
||||
string gamedescription = getgamedirinfo(id, 2);
|
||||
|
||||
/* no manifest, or no cvar strings inside */
|
||||
if (gamedescription == "") {
|
||||
return (0);
|
||||
}
|
||||
|
||||
count = tokenize_console(gamedescription);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
string full = argv(i);
|
||||
string first = substring(full, 0, 9);
|
||||
string second = substring(full, 9, -1);
|
||||
|
||||
/* we may have a game manifest, but if it doesn't
|
||||
* contains any gameinfo entries a different file
|
||||
* should probably be parsed later */
|
||||
if (first == "gameinfo_") {
|
||||
customgame_liblist_parse(id, second, argv(i+1));
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/* check if a liblist, parse it if present */
|
||||
int
|
||||
games_check_liblist(int id, string gamedirname)
|
||||
{
|
||||
string temp;
|
||||
filestream fh;
|
||||
int ret = 0;
|
||||
|
||||
/* first let's see if we've got a liblist.gam just floating inside the gamedir */
|
||||
fh = games_find_in_gamedir("liblist.gam", gamedirname);
|
||||
|
||||
/* we have found a liblist.gam */
|
||||
if (fh >= 0) {
|
||||
while ((temp = fgets(fh))) {
|
||||
tokenize(temp);
|
||||
customgame_liblist_parse(id, argv(0), argv(1));
|
||||
}
|
||||
fclose(fh);
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
void
|
||||
customgame_btnactivate_start(void)
|
||||
{
|
||||
int nextgame = customgame_lbMods.GetSelected();
|
||||
|
||||
games_set(nextgame);
|
||||
|
||||
if (games[nextgame].info_type == GAMEINFO_MANIFEST)
|
||||
localcmd(sprintf("gamedir %s %s.fmf\nfs_changegame %s -\n", games[nextgame].gamedir, games[nextgame].gamedir, games[nextgame].gamedir));
|
||||
else if (games[nextgame].info_type == GAMEINFO_LIBLIST) {
|
||||
/* some games/mods inherit other directories */
|
||||
if (games[nextgame].fallback_dir) {
|
||||
localcmd(sprintf("gamedir \"%s;%s;%s\"\n", games[nextgame].base_dir, games[nextgame].fallback_dir, games[nextgame].gamedir));
|
||||
} else {
|
||||
localcmd(sprintf("gamedir \"%s;%s\"\n", games[nextgame].base_dir, games[nextgame].gamedir));
|
||||
}
|
||||
} else
|
||||
localcmd(sprintf("gamedir \"%s;%s\"\n", games[nextgame].base_dir, games[nextgame].gamedir));
|
||||
|
||||
localcmd("stopmusic\nsnd_restart\nwait\nvid_reload\n");
|
||||
localcmd("menu_restart\n");
|
||||
localcmd("menu_customgame\n");
|
||||
localcmd("menu_musicstart\n");
|
||||
}
|
||||
|
||||
void
|
||||
customgame_installstart(int gameid)
|
||||
{
|
||||
int count;
|
||||
count = tokenize(games[gameid].pkgname);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
int pkgid = game_getpackageid(argv(i));
|
||||
localcmd(sprintf("pkg add %s\n", argv(i)));
|
||||
print(sprintf("Marking package %s for install.\n",
|
||||
argv(i)));
|
||||
}
|
||||
|
||||
game_writeinstallcache(gameid, games[gameid].gamedir);
|
||||
localcmd("pkg apply\n");
|
||||
print("Starting installation of custom game packages\n");
|
||||
}
|
||||
|
||||
void
|
||||
customgame_installend(void)
|
||||
{
|
||||
int gid = g_iModInstallCache;
|
||||
print(sprintf("Installation ended for %S!\n", g_strModInstallCache));
|
||||
localcmd(sprintf("game %s\n", g_strModInstallCache));
|
||||
|
||||
localcmd("stopmusic\nsnd_restart\nwait\nvid_reload\n");
|
||||
localcmd("menu_restart\n");
|
||||
localcmd("menu_customgame\n");
|
||||
localcmd("menu_musicstart\n");
|
||||
game_writeinstallcache(-1, g_strModInstallCache);
|
||||
GameLibrary_Activate(customgame_lbMods.GetSelected());
|
||||
}
|
||||
|
||||
void
|
||||
customgame_installframe(void)
|
||||
{
|
||||
int id;
|
||||
float perc;
|
||||
float c;
|
||||
int loading;
|
||||
|
||||
/* graphical frame */
|
||||
customgame_dlgWait.Draw();
|
||||
WField_Static(162, 180, "Installing mod data...", 320, 260,
|
||||
col_prompt_text, 1.0f, 2, font_label_p);
|
||||
|
||||
/* download percentage */
|
||||
perc = 0.0f;
|
||||
loading = FALSE;
|
||||
|
||||
/* a game can have multiple packages associated */
|
||||
id = g_iModInstallCache;
|
||||
c = tokenize(games[id].pkgname);
|
||||
|
||||
/* go through all invididual packages */
|
||||
for (float i = 0; i < c; i++) {
|
||||
string st;
|
||||
int pkgid;
|
||||
|
||||
/* package query */
|
||||
pkgid = game_getpackageid(argv(i));
|
||||
st = getpackagemanagerinfo(pkgid, GPMI_INSTALLED);
|
||||
|
||||
/* filter out statuses so we can calculate percentage */
|
||||
switch (st) {
|
||||
case "":
|
||||
case "pending":
|
||||
case "enabled":
|
||||
case "present":
|
||||
case "corrupt":
|
||||
break;
|
||||
default:
|
||||
perc += stof(st);
|
||||
}
|
||||
|
||||
/* all packages need to be 'enabled', else fail to end */
|
||||
if (st != "enabled")
|
||||
loading = TRUE;
|
||||
}
|
||||
|
||||
/* display download percentage we calculated */
|
||||
perc = perc / c;
|
||||
WField_Static(162, 220, sprintf("%d%%", perc), 320, 260,
|
||||
WField_Static(162, 220, sprintf("%d%%", GameLibrary_InstallProgress()), 320, 260,
|
||||
[1,1,1], 1.0f, 2, font_label_p);
|
||||
WField_Static(162, 260, "Service provided by frag-net.com through archive.org", 320, 260,
|
||||
[1,1,1], 1.0f, 2, font_label);
|
||||
|
||||
/* not everything has been downloaded */
|
||||
if (loading == TRUE)
|
||||
return;
|
||||
|
||||
customgame_installend();
|
||||
}
|
||||
|
||||
/* download the .fmf and switch games immediately */
|
||||
void
|
||||
customgame_btninstall_start(void)
|
||||
{
|
||||
int id = customgame_lbMods.GetSelected();
|
||||
string st;
|
||||
|
||||
st = getpackagemanagerinfo(games[id].pkgid, GPMI_INSTALLED);
|
||||
|
||||
print(st);
|
||||
print("\n");
|
||||
|
||||
if (st != "enabled") {
|
||||
customgame_installstart(id);
|
||||
return;
|
||||
}
|
||||
|
||||
game_writeinstallcache(id, games[id].gamedir);
|
||||
customgame_installend();
|
||||
GameLibrary_Install(customgame_lbMods.GetSelected());
|
||||
}
|
||||
|
||||
void
|
||||
customgame_btndeactivate_start(void)
|
||||
{
|
||||
localcmd(sprintf("gamedir %s\n", GAME_DIR));
|
||||
localcmd("stopmusic\nsnd_restart\nwait\nvid_reload\n");
|
||||
localcmd("menu_restart\n");
|
||||
localcmd("menu_customgame\n");
|
||||
localcmd("menu_musicstart\n");
|
||||
GameLibrary_Deactivate();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -717,160 +97,6 @@ customgame_lbmods_changed(void)
|
|||
}
|
||||
}
|
||||
|
||||
/* set some sane default packages, so that we don't need to ship a custom liblist */
|
||||
void
|
||||
games_setdefaultpkgs(int id)
|
||||
{
|
||||
#if 0
|
||||
if (games[id].gamedir == "valve") {
|
||||
games[id].pkgname = "valve_patch;addon_furtherdata;addon_holidaymodels";
|
||||
games[id].pkgfile = "maps/crossfire.bsp"; /* only found in patches */
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
games_init_mods(void)
|
||||
{
|
||||
int id;
|
||||
int foundself = 0;
|
||||
string gamedirname;
|
||||
gameinfo_count = 0;
|
||||
|
||||
for (id = 0; (gamedirname = getgamedirinfo(id, 0)); id++) {
|
||||
gameinfo_count++;
|
||||
}
|
||||
|
||||
/* re-allocate the game list */
|
||||
memfree(games);
|
||||
games = memalloc(sizeof(gameinfo_t) * gameinfo_count);
|
||||
|
||||
/* The things we do for frequent flyer mileage. */
|
||||
if (!games)
|
||||
error(sprintf("Attempting to allocate mod data for %i entries failed\n", gameinfo_count));
|
||||
|
||||
/* now loop through all the mods we found and load in the metadata */
|
||||
for (id = 0; id < gameinfo_count; id++) {
|
||||
gamedirname = getgamedirinfo(id, 0);
|
||||
|
||||
/* Fill in the defaults */
|
||||
games[id].game = gamedirname;
|
||||
games[id].gamedir = gamedirname;
|
||||
games[id].base_dir = GAME_DIR;
|
||||
games[id].url_info = "";
|
||||
games[id].url_dl = "";
|
||||
games[id].version = "1.0";
|
||||
games[id].size = 0;
|
||||
games[id].type = "Both";
|
||||
games[id].nomodels = 0;
|
||||
games[id].nosprays = 0;
|
||||
games[id].mpentity = "info_player_deathmatch";
|
||||
games[id].gamedll = "progs.dat";
|
||||
games[id].startmap = "map c0a0\n";
|
||||
games[id].trainingmap = "map t0a0\n";
|
||||
games[id].cldll = 1;
|
||||
games[id].hlversion = "1000";
|
||||
games[id].svonly = 0;
|
||||
games[id].installed = 1;
|
||||
games[id].chatroom = gamedirname;
|
||||
games[id].readme = "readme.txt";
|
||||
games[id].pkgid = -1;
|
||||
games[id].steambg = 0;
|
||||
|
||||
games_setdefaultpkgs(id);
|
||||
|
||||
if (games_check_manifest(id, gamedirname) == 1) {
|
||||
NSLog("[MENU] Found manifest for %s", gamedirname);
|
||||
games[id].info_type = GAMEINFO_MANIFEST;
|
||||
} else if (games_check_gtxt(id, gamedirname) == 1) {
|
||||
NSLog("[MENU] Found gameinfo for %s", gamedirname);
|
||||
games[id].info_type = GAMEINFO_GITXT;
|
||||
} else if (games_check_liblist(id, gamedirname) == 1) {
|
||||
NSLog("[MENU] Found liblist for %s", gamedirname);
|
||||
games[id].info_type = GAMEINFO_LIBLIST;
|
||||
} else {
|
||||
NSLog("[MENU] Found nothing for %s", gamedirname);
|
||||
games[id].info_type = GAMEINFO_NONE;
|
||||
}
|
||||
|
||||
/* if we're this mod, make sure to let the rest of the menu know */
|
||||
if (games[id].gamedir == cvar_string("game")) {
|
||||
games_set(id);
|
||||
}
|
||||
}
|
||||
|
||||
/* we may have some mods, but we're not running any of them. Fatal */
|
||||
if (gameinfo_current == -1) {
|
||||
print("^1FATAL ERROR: NO LIBLIST.GAM FOR CURRENT MOD FOUND!\n");
|
||||
crash();
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
games_init(void)
|
||||
{
|
||||
int id = 0;
|
||||
string gamedirname = cvar_string("game");
|
||||
|
||||
gameinfo_count = 1; /* we start at 1 game, ours */
|
||||
games = memalloc(sizeof(gameinfo_t) * gameinfo_count);
|
||||
|
||||
/* Fill in the defaults */
|
||||
games[id].game = gamedirname;
|
||||
games[id].gamedir = gamedirname;
|
||||
games[id].base_dir = GAME_DIR;
|
||||
games[id].url_info = "";
|
||||
games[id].url_dl = "";
|
||||
games[id].version = "1.0";
|
||||
games[id].size = 0;
|
||||
games[id].type = "Both";
|
||||
games[id].nomodels = 0;
|
||||
games[id].nosprays = 0;
|
||||
games[id].mpentity = "info_player_deathmatch";
|
||||
games[id].gamedll = "progs.dat";
|
||||
games[id].startmap = "map c0a0\n";
|
||||
games[id].trainingmap = "map t0a0\n";
|
||||
games[id].cldll = 1;
|
||||
games[id].hlversion = "1000";
|
||||
games[id].svonly = 0;
|
||||
games[id].installed = 1;
|
||||
games[id].chatroom = cvar_string("gameinfo_chatroom");
|
||||
|
||||
if not (games[id].chatroom) {
|
||||
games[id].chatroom = gamedirname;
|
||||
}
|
||||
|
||||
games[id].readme = "readme.txt";
|
||||
games[id].pkgid = -1;
|
||||
games[id].steambg = 0;
|
||||
gameinfo_current = 0;
|
||||
|
||||
/* only run this when not in web-client mode */
|
||||
#ifndef WEBMENU
|
||||
/* set the default packages for a given game */
|
||||
games_setdefaultpkgs(id);
|
||||
|
||||
if (games_check_manifest(id, gamedirname) == 1) {
|
||||
NSLog("[MENU] Found manifest for %s", gamedirname);
|
||||
games[id].info_type = GAMEINFO_MANIFEST;
|
||||
} else if (games_check_gtxt(id, gamedirname) == 1) {
|
||||
NSLog("[MENU] Found gameinfo for %s", gamedirname);
|
||||
games[id].info_type = GAMEINFO_GITXT;
|
||||
} else if (games_check_liblist(id, gamedirname) == 1) {
|
||||
NSLog("[MENU] Found liblist for %s", gamedirname);
|
||||
games[id].info_type = GAMEINFO_LIBLIST;
|
||||
} else {
|
||||
NSLog("[MENU] Found nothing for %s", gamedirname);
|
||||
games[id].info_type = GAMEINFO_NONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* set the current game to be us */
|
||||
games_set(id);
|
||||
}
|
||||
|
||||
void
|
||||
menu_customgame_init(void)
|
||||
{
|
||||
|
@ -930,7 +156,6 @@ menu_customgame_init(void)
|
|||
customgame_sbMods.SetCallback(customgame_sbmods_changed);
|
||||
customgame_sbMods.SetMax(gameinfo_count);
|
||||
Widget_Add(fn_customgame, customgame_sbMods);
|
||||
g_iModInstallCache = -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -950,9 +175,9 @@ menu_customgame_draw(void)
|
|||
WField_Static(162, 180, "Indexing all local games, please wait...", 320, 260,
|
||||
col_prompt_text, 1.0f, 2, font_label_p);
|
||||
|
||||
/* once we started rendering the message, start parsing mods */
|
||||
/* once we started rendering the message, start parsing mods (stalls) */
|
||||
if (g_customgame_initialized == 1)
|
||||
games_init_mods();
|
||||
GameLibrary_InitCustom();
|
||||
|
||||
g_customgame_initialized++;
|
||||
return;
|
||||
|
@ -986,7 +211,7 @@ menu_customgame_draw(void)
|
|||
|
||||
|
||||
/* draw a frame with progress during package install */
|
||||
if (g_iModInstallCache >= 0i) {
|
||||
if (GameLibrary_IsInstalling()) {
|
||||
customgame_installframe();
|
||||
}
|
||||
|
||||
|
|
|
@ -22,4 +22,5 @@
|
|||
#include "richpresence.h"
|
||||
#include "servers.h"
|
||||
#include "tcp.h"
|
||||
#include "updates.h"
|
||||
#include "updates.h"
|
||||
#include "gamelibrary.h"
|
33
src/platform/gamelibrary.h
Normal file
33
src/platform/gamelibrary.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (c) 2016-2023 Vera Visions LLC.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/** Called when initializing the current game. Does not cache custom game/mod info. */
|
||||
void GameLibrary_Init(void);
|
||||
/** Called when you want to initialize custom games/mods. Might want to call this later
|
||||
if the amount of locally installed mods is overwhelming. */
|
||||
void GameLibrary_InitCustom(void);
|
||||
|
||||
/** Install the specified game. */
|
||||
void GameLibrary_Install(int);
|
||||
/** Activate the specified game. */
|
||||
void GameLibrary_Activate(int);
|
||||
/** Deactivate the currently running mod. Switching back to the base game. */
|
||||
void GameLibrary_Deactivate(void);
|
||||
|
||||
/** Returns true/false depending on if a Game installation is in progress. */
|
||||
bool GameLibrary_IsInstalling(void);
|
||||
/** Returns a 0-100% value of game install progress, tracking across multiple packages. */
|
||||
float GameLibrary_InstallProgress(void);
|
626
src/platform/gamelibrary.qc
Normal file
626
src/platform/gamelibrary.qc
Normal file
|
@ -0,0 +1,626 @@
|
|||
/*
|
||||
* Copyright (c) 2016-2023 Vera Visions LLC.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
int g_iModInstallCache;
|
||||
string g_strModInstallCache;
|
||||
|
||||
/* local game/mod info parsing */
|
||||
static void
|
||||
GameLibrary_Set(int id)
|
||||
{
|
||||
gameinfo_current = id;
|
||||
setwindowcaption(games[id].game);
|
||||
cvar_set("com_fullgamename", games[id].game);
|
||||
}
|
||||
|
||||
/** Looks for a single file inside a gamedir, including its pk3s and returns a valid filehandle if it is found. */
|
||||
static filestream
|
||||
GameLibrary_FindInGameDir(string filename, string gamedirname)
|
||||
{
|
||||
searchhandle sh;
|
||||
searchhandle gsh;
|
||||
searchhandle psh;
|
||||
filestream fh;
|
||||
|
||||
/* if we're querying a file in our mounted game, we can exit early */
|
||||
if (gamedirname == cvar_string("fs_game")) {
|
||||
fh = fopen(filename, FILE_READ);
|
||||
|
||||
if (fh >= 0) {
|
||||
return fh;
|
||||
}
|
||||
}
|
||||
|
||||
/* first let's see if we've got a liblist.gam just floating inside the gamedir */
|
||||
gsh = search_begin(filename, SB_FULLPACKAGEPATH | SB_FORCESEARCH | SEARCH_ALLOWDUPES, FALSE, gamedirname);
|
||||
fh = search_fopen(gsh, 0);
|
||||
|
||||
/* we do not. let's search for pk3's to sift through */
|
||||
if (fh < 0) {
|
||||
/* let's search for every pk3 in the gamedir and search for a liblist, one at a time. */
|
||||
psh = search_begin("*.pk3", SB_FULLPACKAGEPATH | SB_FORCESEARCH, FALSE, gamedirname);
|
||||
|
||||
/* loop through each pk3 in reverse (newest to old) */
|
||||
for (int i = search_getsize(psh); i >= 0; i--) {
|
||||
string full = search_getfilename(psh, i);
|
||||
|
||||
if (!full)
|
||||
continue;
|
||||
|
||||
sh = search_begin(filename, SB_FULLPACKAGEPATH | SB_FORCESEARCH, FALSE, strcat(gamedirname, "/", full));
|
||||
fh = search_fopen(sh, 0);
|
||||
//print(sprintf("looking for %s in %s\n", filename, strcat(gamedirname, "/", full)));
|
||||
|
||||
/* we found one */
|
||||
if (fh >= 0) {
|
||||
search_end(sh);
|
||||
break;
|
||||
}
|
||||
search_end(sh);
|
||||
}
|
||||
search_end(psh);
|
||||
}
|
||||
|
||||
/* still nothing. let's search for pk4's to sift through */
|
||||
if (fh < 0) {
|
||||
/* let's search for every pk4 in the gamedir and search for a liblist, one at a time. */
|
||||
psh = search_begin("*.pk4", SB_FULLPACKAGEPATH | SB_FORCESEARCH | SEARCH_ALLOWDUPES, FALSE, gamedirname);
|
||||
|
||||
/* loop through each pk4 in reverse (newest to old) */
|
||||
for (int i = search_getsize(psh); i >= 0; i--) {
|
||||
string full = search_getfilename(psh, i);
|
||||
|
||||
if (!full)
|
||||
continue;
|
||||
|
||||
sh = search_begin(filename, SB_FULLPACKAGEPATH | SB_FORCESEARCH | SEARCH_ALLOWDUPES, FALSE, strcat(gamedirname, "/", full));
|
||||
fh = search_fopen(sh, 0);
|
||||
|
||||
/* we found one */
|
||||
if (fh >= 0) {
|
||||
search_end(sh);
|
||||
break;
|
||||
}
|
||||
search_end(sh);
|
||||
}
|
||||
search_end(psh);
|
||||
}
|
||||
|
||||
search_end(gsh);
|
||||
return (fh);
|
||||
}
|
||||
|
||||
#ifndef WEBMENU
|
||||
/** Parses a key/value pair from liblist.gam files */
|
||||
static void
|
||||
GameLibrary_LibListParse(int id, string strKey, string strValue)
|
||||
{
|
||||
if (id == 0)
|
||||
print(sprintf("%i %S %S\n", id, strKey, strValue));
|
||||
|
||||
switch(strKey) {
|
||||
case "game":
|
||||
games[id].game = strValue;
|
||||
break;
|
||||
case "gamedir":
|
||||
games[id].gamedir = strValue;
|
||||
break;
|
||||
case "fallback_dir":
|
||||
games[id].fallback_dir = strValue;
|
||||
break;
|
||||
case "url_info":
|
||||
games[id].url_info = strValue;
|
||||
break;
|
||||
case "url_dl":
|
||||
games[id].url_dl = strValue;
|
||||
break;
|
||||
case "version":
|
||||
games[id].version = strValue;
|
||||
break;
|
||||
case "size":
|
||||
games[id].size = (int)stof(strValue);
|
||||
break;
|
||||
case "svonly":
|
||||
games[id].svonly = (int)stof(strValue);
|
||||
break;
|
||||
case "cldll":
|
||||
games[id].cldll = (int)stof(strValue);
|
||||
break;
|
||||
case "type":
|
||||
switch (strtolower(strValue)) {
|
||||
case "multiplayer_only":
|
||||
case "multiplayer only":
|
||||
games[id].type = "Multiplayer";
|
||||
break;
|
||||
case "singleplayer_only":
|
||||
case "singleplayer only":
|
||||
games[id].type = "Singleplayer";
|
||||
break;
|
||||
/* this... kind of sucks, but some games (gearbox) never updated
|
||||
* their liblist to reflect that they do multiplayer */
|
||||
case "sp":
|
||||
case "single":
|
||||
case "singleplayer":
|
||||
case "mp":
|
||||
case "multi":
|
||||
case "multiplayer":
|
||||
default:
|
||||
games[id].type = "Both";
|
||||
}
|
||||
break;
|
||||
case "minversion":
|
||||
case "hlversion":
|
||||
games[id].hlversion = strValue;
|
||||
break;
|
||||
case "nomodels":
|
||||
games[id].nomodels = (int)stof(strValue);
|
||||
break;
|
||||
case "nosprays":
|
||||
games[id].nosprays = (int)stof(strValue);
|
||||
break;
|
||||
case "mpentity":
|
||||
games[id].mpentity = strValue;
|
||||
break;
|
||||
case "gamedll":
|
||||
games[id].gamedll = strValue;
|
||||
break;
|
||||
case "startmap":
|
||||
games[id].startmap = strcat("map ", strValue, "\n");
|
||||
break;
|
||||
case "trainingmap":
|
||||
games[id].trainingmap = strcat("map ", strValue, "\n");
|
||||
break;
|
||||
/* newly added with Nuclide */
|
||||
case "pkgname":
|
||||
games[id].pkgname = strValue;
|
||||
games[id].pkgid = Updates_IDForName(games[id].pkgname);
|
||||
break;
|
||||
case "pkgfile":
|
||||
games[id].pkgfile = strValue;
|
||||
break;
|
||||
case "chatroom":
|
||||
games[id].chatroom = strValue;
|
||||
break;
|
||||
case "readme":
|
||||
games[id].readme = strValue;
|
||||
break;
|
||||
case "menumap":
|
||||
games[id].menumap = strValue;
|
||||
break;
|
||||
case "introvideo":
|
||||
games[id].introvideo = strValue;
|
||||
break;
|
||||
case "steambg":
|
||||
games[id].steambg = (int)stof(strValue);
|
||||
break;
|
||||
case "base_dir":
|
||||
games[id].base_dir = strValue;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** Check if a gameinfo.txt for the gamedir contains gameinfo, parse it if present. Returns true on success. */
|
||||
static bool
|
||||
GameLibrary_CheckGameInfo(int id, string gamedirname)
|
||||
{
|
||||
string temp;
|
||||
filestream fh;
|
||||
int ret = 0;
|
||||
|
||||
fh = GameLibrary_FindInGameDir("gameinfo.txt", gamedirname);
|
||||
|
||||
if (fh < 0)
|
||||
fh = GameLibrary_FindInGameDir("GameInfo.txt", gamedirname);
|
||||
|
||||
/* we have found a liblist.gam */
|
||||
if (fh >= 0) {
|
||||
string gamedirchain = "";
|
||||
int braced = 0;
|
||||
|
||||
while ((temp = fgets(fh))) {
|
||||
string token;
|
||||
tokenize_console(temp);
|
||||
token = strtolower(argv(0));
|
||||
|
||||
if (!token)
|
||||
continue;
|
||||
|
||||
if (token == "{")
|
||||
braced++;
|
||||
|
||||
if (token == "}")
|
||||
braced--;
|
||||
|
||||
if (braced == 1) {
|
||||
/* GameInfo */
|
||||
switch (token) {
|
||||
case "game":
|
||||
games[id].game = argv(1);
|
||||
break;
|
||||
case "type":
|
||||
games[id].type = argv(1);
|
||||
break;
|
||||
}
|
||||
} else if (braced == 2) {
|
||||
/* FileSystem */
|
||||
switch (token) {
|
||||
case "steamappid":
|
||||
break;
|
||||
case "toolsappid":
|
||||
break;
|
||||
}
|
||||
} else if (braced == 3) {
|
||||
/* SearchPaths */
|
||||
switch (token) {
|
||||
case "game":
|
||||
if (argv(1) == "|gameinfo_path|.")
|
||||
gamedirchain = strcat(gamedirchain, games[id].gamedir, " ");
|
||||
else
|
||||
gamedirchain = strcat(gamedirchain, argv(1), " ");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* in gameinfo.txt files, we list game load-order in reverse */
|
||||
if (gamedirchain) {
|
||||
string maindir = games[id].gamedir;
|
||||
float c = tokenize(gamedirchain);
|
||||
|
||||
for (float i = c-1; i >= 0; i--) {
|
||||
if (argv(i) == maindir)
|
||||
continue;
|
||||
|
||||
if (i == 0)
|
||||
games[id].gamedir = strcat(games[id].gamedir, argv(i));
|
||||
else
|
||||
games[id].gamedir = strcat(games[id].gamedir, argv(i), ";");
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fh);
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/** Check if a manifest for the gamedir contains gameinfo, parse it if present. Returns true on success. */
|
||||
static bool
|
||||
GameLibrary_CheckManifest(int id, string gamedirname)
|
||||
{
|
||||
int ret = 0;
|
||||
float count;
|
||||
|
||||
string gamedescription = getgamedirinfo(id, 2);
|
||||
|
||||
/* no manifest, or no cvar strings inside */
|
||||
if (gamedescription == "") {
|
||||
return (0);
|
||||
}
|
||||
|
||||
count = tokenize_console(gamedescription);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
string full = argv(i);
|
||||
string first = substring(full, 0, 9);
|
||||
string second = substring(full, 9, -1);
|
||||
|
||||
/* we may have a game manifest, but if it doesn't
|
||||
* contains any gameinfo entries a different file
|
||||
* should probably be parsed later */
|
||||
if (first == "gameinfo_") {
|
||||
GameLibrary_LibListParse(id, second, argv(i+1));
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/** Check if a liblist exists, and parse it if present. Returns true on success. */
|
||||
static bool
|
||||
GameLibrary_CheckLibList(int id, string gamedirname)
|
||||
{
|
||||
string temp;
|
||||
filestream fh;
|
||||
int ret = 0;
|
||||
|
||||
/* first let's see if we've got a liblist.gam just floating inside the gamedir */
|
||||
fh = GameLibrary_FindInGameDir("liblist.gam", gamedirname);
|
||||
|
||||
/* we have found a liblist.gam */
|
||||
if (fh >= 0) {
|
||||
while ((temp = fgets(fh))) {
|
||||
tokenize(temp);
|
||||
GameLibrary_LibListParse(id, argv(0), argv(1));
|
||||
}
|
||||
fclose(fh);
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/** Set some sane game defaults into a game id slot based on gamedir name. */
|
||||
static void
|
||||
GameLibrary_SetDefaults(int id, string gamedirname)
|
||||
{
|
||||
/* Fill in the defaults */
|
||||
games[id].game = gamedirname;
|
||||
games[id].gamedir = gamedirname;
|
||||
games[id].base_dir = GAME_DIR;
|
||||
games[id].url_info = "";
|
||||
games[id].url_dl = "";
|
||||
games[id].version = "1.0";
|
||||
games[id].size = 0;
|
||||
games[id].type = "Both";
|
||||
games[id].nomodels = 0;
|
||||
games[id].nosprays = 0;
|
||||
games[id].mpentity = "info_player_deathmatch";
|
||||
games[id].gamedll = "progs.dat";
|
||||
games[id].startmap = "map c0a0\n";
|
||||
games[id].trainingmap = "map t0a0\n";
|
||||
games[id].cldll = 1;
|
||||
games[id].hlversion = "1000";
|
||||
games[id].svonly = 0;
|
||||
games[id].installed = 1;
|
||||
games[id].chatroom = gamedirname;
|
||||
games[id].readme = "readme.txt";
|
||||
games[id].pkgid = -1;
|
||||
games[id].steambg = 0;
|
||||
|
||||
#if 0
|
||||
if (games[id].gamedir == "valve") {
|
||||
games[id].pkgname = "valve_patch;addon_furtherdata;addon_holidaymodels";
|
||||
games[id].pkgfile = "maps/crossfire.bsp"; /* only found in patches */
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
GameLibrary_InitCustom(void)
|
||||
{
|
||||
int id;
|
||||
int foundself = 0;
|
||||
string gamedirname;
|
||||
gameinfo_count = 0;
|
||||
|
||||
for (id = 0; (gamedirname = getgamedirinfo(id, 0)); id++) {
|
||||
gameinfo_count++;
|
||||
}
|
||||
|
||||
/* re-allocate the game list */
|
||||
memfree(games);
|
||||
games = memalloc(sizeof(gameinfo_t) * gameinfo_count);
|
||||
|
||||
/* The things we do for frequent flyer mileage. */
|
||||
if (!games)
|
||||
error(sprintf("Attempting to allocate mod data for %i entries failed\n", gameinfo_count));
|
||||
|
||||
/* now loop through all the mods we found and load in the metadata */
|
||||
for (id = 0; id < gameinfo_count; id++) {
|
||||
gamedirname = getgamedirinfo(id, 0);
|
||||
GameLibrary_SetDefaults(id, gamedirname);
|
||||
|
||||
if (GameLibrary_CheckManifest(id, gamedirname) == true) {
|
||||
NSLog("[MENU] Found manifest for %s", gamedirname);
|
||||
games[id].info_type = GAMEINFO_MANIFEST;
|
||||
} else if (GameLibrary_CheckGameInfo(id, gamedirname) == true) {
|
||||
NSLog("[MENU] Found gameinfo for %s", gamedirname);
|
||||
games[id].info_type = GAMEINFO_GITXT;
|
||||
} else if (GameLibrary_CheckLibList(id, gamedirname) == true) {
|
||||
NSLog("[MENU] Found liblist for %s", gamedirname);
|
||||
games[id].info_type = GAMEINFO_LIBLIST;
|
||||
} else {
|
||||
NSLog("[MENU] Found nothing for %s", gamedirname);
|
||||
games[id].info_type = GAMEINFO_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
/* we may have some mods, but we're not running any of them. Fatal */
|
||||
if (gameinfo_current == -1) {
|
||||
print("^1FATAL ERROR: NO LIBLIST.GAM FOR CURRENT MOD FOUND!\n");
|
||||
crash();
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
GameLibrary_Init(void)
|
||||
{
|
||||
int id = 0i;
|
||||
string gamedirname = cvar_string("game");
|
||||
|
||||
g_iModInstallCache = -1;
|
||||
g_strModInstallCache = __NULL__;
|
||||
gameinfo_count = 1; /* we start at 1 game, ours */
|
||||
games = memalloc(sizeof(gameinfo_t) * gameinfo_count);
|
||||
|
||||
/* set the default packages for a given game */
|
||||
GameLibrary_SetDefaults(id, gamedirname);
|
||||
|
||||
gameinfo_current = 0i;
|
||||
|
||||
/* only run this when not in web-client mode */
|
||||
#ifndef WEBMENU
|
||||
|
||||
if (GameLibrary_CheckManifest(id, gamedirname) == 1) {
|
||||
NSLog("[MENU] Found manifest for %s", gamedirname);
|
||||
games[id].info_type = GAMEINFO_MANIFEST;
|
||||
} else if (GameLibrary_CheckGameInfo(id, gamedirname) == 1) {
|
||||
NSLog("[MENU] Found gameinfo for %s", gamedirname);
|
||||
games[id].info_type = GAMEINFO_GITXT;
|
||||
} else if (GameLibrary_CheckLibList(id, gamedirname) == 1) {
|
||||
NSLog("[MENU] Found liblist for %s", gamedirname);
|
||||
games[id].info_type = GAMEINFO_LIBLIST;
|
||||
} else {
|
||||
NSLog("[MENU] Found nothing for %s", gamedirname);
|
||||
games[id].info_type = GAMEINFO_NONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* set the current game to be us */
|
||||
GameLibrary_Set(id);
|
||||
}
|
||||
|
||||
static void
|
||||
GameLibrary_EndInstall(void)
|
||||
{
|
||||
int gid = g_iModInstallCache;
|
||||
print(sprintf("Installation ended for %S!\n", g_strModInstallCache));
|
||||
localcmd(sprintf("game %s\n", g_strModInstallCache));
|
||||
|
||||
localcmd("stopmusic\nsnd_restart\nwait\nvid_reload\n");
|
||||
localcmd("menu_restart\n");
|
||||
localcmd("menu_customgame\n");
|
||||
localcmd("menu_musicstart\n");
|
||||
g_iModInstallCache = -1i;
|
||||
g_strModInstallCache = __NULL__;
|
||||
}
|
||||
|
||||
bool
|
||||
GameLibrary_IsInstalling(void)
|
||||
{
|
||||
return (g_iModInstallCache == -1i) ? false : true;
|
||||
}
|
||||
|
||||
float
|
||||
GameLibrary_InstallProgress(void)
|
||||
{
|
||||
int id;
|
||||
float perc;
|
||||
float c;
|
||||
bool loading = false;
|
||||
|
||||
/* download percentage */
|
||||
perc = 0.0f;
|
||||
loading = FALSE;
|
||||
|
||||
/* a game can have multiple packages associated */
|
||||
id = g_iModInstallCache;
|
||||
c = tokenize(games[id].pkgname);
|
||||
|
||||
/* go through all invididual packages */
|
||||
for (float i = 0; i < c; i++) {
|
||||
string st;
|
||||
int pkgid;
|
||||
|
||||
/* package query */
|
||||
pkgid = Updates_IDForName(argv(i));
|
||||
st = Updates_GetInfo(pkgid, GPMI_INSTALLED);
|
||||
|
||||
/* filter out statuses so we can calculate percentage */
|
||||
switch (st) {
|
||||
case "":
|
||||
case "pending":
|
||||
case "enabled":
|
||||
case "present":
|
||||
case "corrupt":
|
||||
break;
|
||||
default:
|
||||
perc += stof(st);
|
||||
}
|
||||
|
||||
/* all packages need to be 'enabled', else fail to end */
|
||||
if (st != "enabled")
|
||||
loading = true;
|
||||
}
|
||||
|
||||
/* not everything has been downloaded */
|
||||
if (loading == TRUE)
|
||||
return perc / c;
|
||||
|
||||
GameLibrary_EndInstall();
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
GameLibrary_InstallStart(int gameid)
|
||||
{
|
||||
int count;
|
||||
count = tokenize(games[gameid].pkgname);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
int pkgid = Updates_IDForName(argv(i));
|
||||
localcmd(sprintf("pkg add %s\n", argv(i)));
|
||||
print(sprintf("Marking package %s for install.\n",
|
||||
argv(i)));
|
||||
}
|
||||
|
||||
g_iModInstallCache = gameid;
|
||||
g_strModInstallCache = games[gameid].gamedir;
|
||||
localcmd("pkg apply\n");
|
||||
print("Starting installation of custom game packages\n");
|
||||
}
|
||||
|
||||
void
|
||||
GameLibrary_Install(int gameID)
|
||||
{
|
||||
string st;
|
||||
|
||||
st = Updates_GetInfo(games[gameID].pkgid, GPMI_INSTALLED);
|
||||
|
||||
print(st);
|
||||
print("\n");
|
||||
|
||||
if (st != "enabled") {
|
||||
GameLibrary_InstallStart(gameID);
|
||||
return;
|
||||
}
|
||||
|
||||
g_iModInstallCache = gameID;
|
||||
g_strModInstallCache = games[gameID].gamedir;
|
||||
GameLibrary_EndInstall();
|
||||
}
|
||||
|
||||
void
|
||||
GameLibrary_Activate(int gameID)
|
||||
{
|
||||
GameLibrary_Set(gameID);
|
||||
|
||||
if (games[gameID].info_type == GAMEINFO_MANIFEST)
|
||||
localcmd(sprintf("gamedir %s %s.fmf\nfs_changegame %s -\n", games[gameID].gamedir, games[gameID].gamedir, games[gameID].gamedir));
|
||||
else if (games[gameID].info_type == GAMEINFO_LIBLIST) {
|
||||
/* some games/mods inherit other directories */
|
||||
if (games[gameID].fallback_dir) {
|
||||
localcmd(sprintf("gamedir \"%s;%s;%s\"\n", games[gameID].base_dir, games[gameID].fallback_dir, games[gameID].gamedir));
|
||||
} else {
|
||||
localcmd(sprintf("gamedir \"%s;%s\"\n", games[gameID].base_dir, games[gameID].gamedir));
|
||||
}
|
||||
} else
|
||||
localcmd(sprintf("gamedir \"%s;%s\"\n", games[gameID].base_dir, games[gameID].gamedir));
|
||||
|
||||
localcmd("stopmusic\nsnd_restart\nwait\nvid_reload\n");
|
||||
localcmd("menu_restart\n");
|
||||
localcmd("menu_customgame\n");
|
||||
localcmd("menu_musicstart\n");
|
||||
}
|
||||
|
||||
void
|
||||
GameLibrary_Deactivate(void)
|
||||
{
|
||||
localcmd(sprintf("gamedir %s\n", GAME_DIR));
|
||||
localcmd("stopmusic\nsnd_restart\nwait\nvid_reload\n");
|
||||
localcmd("menu_restart\n");
|
||||
localcmd("menu_customgame\n");
|
||||
localcmd("menu_musicstart\n");
|
||||
}
|
|
@ -8,4 +8,5 @@ servers.qc
|
|||
tcp.qc
|
||||
util.qc
|
||||
updates.qc
|
||||
gamelibrary.qc
|
||||
#endlist
|
||||
|
|
|
@ -29,8 +29,6 @@
|
|||
var int g_iModServerLoading;
|
||||
var int g_iModServerReqCount;
|
||||
|
||||
int game_getpackageid(string pkgname);
|
||||
|
||||
/** Call this to initiate a lengthy process of updating the list of mods
|
||||
we can install in the custom game menu. */
|
||||
void ModServer_Refresh(void);
|
||||
|
|
|
@ -161,7 +161,7 @@ ModServer_ParseItem(string data)
|
|||
break;
|
||||
case "gameinfo_pkgname":
|
||||
games[id].pkgname = argv(i+1);
|
||||
games[id].pkgid = game_getpackageid(games[id].pkgname);
|
||||
games[id].pkgid = Updates_IDForName(games[id].pkgname);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -92,14 +92,22 @@ Updates_Refresh(void)
|
|||
int
|
||||
Updates_IDForName(string packageName)
|
||||
{
|
||||
string tempString = "";
|
||||
string f;
|
||||
|
||||
for (int i = 0i; (tempString = getpackagemanagerinfo(i, GPMI_NAME)); i++) {
|
||||
if (tempString == packageName)
|
||||
for (int i = 0; (getpackagemanagerinfo(i, GPMI_NAME)); i++) {
|
||||
string name;
|
||||
name = getpackagemanagerinfo(i, GPMI_NAME);
|
||||
|
||||
/* Spike started randomly putting version numbers into package names */
|
||||
f = sprintf("%s=%s", packageName, getpackagemanagerinfo(i, GPMI_VERSION));
|
||||
|
||||
if (name == f) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1i;
|
||||
/* no package id whatsoever */
|
||||
return (-1i);
|
||||
}
|
||||
|
||||
/** Returns the package name for a given ID. Returns __NULL__ when not available. */
|
||||
|
|
Loading…
Reference in a new issue