Platform/Menu-FN: Overhaul of game update handling. New Nuclide specific API to query update package states that avoids string comparisons and much more.
This commit is contained in:
parent
8422ddd26b
commit
412c8f984e
10 changed files with 645 additions and 229 deletions
|
@ -958,7 +958,7 @@ msgid "IDS_CONFIGURE_GOREHELP"
|
|||
msgstr "Disable visuals inappropriate for younger players and multiplayer."
|
||||
|
||||
msgid "IDS_CONFIGURE_AUTOPATCHHELP"
|
||||
msgstr "Download the latest version of %s."
|
||||
msgstr "Download updates for %s."
|
||||
|
||||
msgid "IDS_CHAT_NOSERVERS"
|
||||
msgstr "Could not locate any Frag-Net servers."
|
||||
|
@ -1652,3 +1652,33 @@ msgstr "Do you want to uncompress the files for game '%s'?"
|
|||
|
||||
msgid "IDS_FAVSVRS_CORRUPT"
|
||||
msgstr "The server data file favsvrs.dat appears to be corrupt.\n\nYou can request a new list of servers by pressing the Update button.\n\nDo you want to remove the corrupt file (you will have to re-enter your 'favorites' if you remove the file)?"
|
||||
|
||||
msgid "UPDATE_DISABLED"
|
||||
msgstr "Disabled"
|
||||
|
||||
msgid "UPDATE_ENABLED"
|
||||
msgstr "Enabled"
|
||||
|
||||
msgid "UPDATE_CORRUPT"
|
||||
msgstr "Corrupt"
|
||||
|
||||
msgid "UPDATE_NOTINSTALLED"
|
||||
msgstr "Not installed"
|
||||
|
||||
msgid "UPDATE_PENDING_INSTALL"
|
||||
msgstr "Install (pending)"
|
||||
|
||||
msgid "UPDATE_PENDING_REINSTALL"
|
||||
msgstr "Reinstall (pending)"
|
||||
|
||||
msgid "UPDATE_PENDING_UNINSTALL"
|
||||
msgstr "Uninstall (pending)"
|
||||
|
||||
msgid "UPDATE_PENDING_AUTOINSTALL"
|
||||
msgstr "Auto-install (pending)"
|
||||
|
||||
msgid "UPDATE_PENDING_DISABLE"
|
||||
msgstr "Disable (pending)"
|
||||
|
||||
msgid "UPDATE_PENDING_RETAIN"
|
||||
msgstr "Retain (pending)"
|
|
@ -138,7 +138,6 @@ m_init(void)
|
|||
|
||||
Colors_Init();
|
||||
Strings_Init();
|
||||
Updates_Init();
|
||||
|
||||
if (GameLibrary_GetInfo(GAMEINFO_GAMEDIR) != "valve") {
|
||||
m_intro_skip();
|
||||
|
|
|
@ -38,19 +38,19 @@ up_btndone_start(void)
|
|||
cvar_set("menu_updating", "0");
|
||||
localsound("../media/launch_dnmenu1.wav");
|
||||
g_menupage = PAGE_CONFIGURATION;
|
||||
localcmd("seta menu_installedpackages 1;cfg_save\n");
|
||||
localcmd("pkg revert;seta menu_installedpackages 1;cfg_save\n");
|
||||
}
|
||||
|
||||
void
|
||||
up_btninstall_start(void)
|
||||
{
|
||||
Updates_Remove(up_lbUpdates.GetSelected());
|
||||
Updates_Install(up_lbUpdates.GetSelected());
|
||||
}
|
||||
|
||||
void
|
||||
up_btnremove_start(void)
|
||||
{
|
||||
Updates_Install(up_lbUpdates.GetSelected());
|
||||
Updates_Destroy(up_lbUpdates.GetSelected());
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -76,7 +76,7 @@ up_lbupdates_changed(void)
|
|||
if (pkgid == -1)
|
||||
return;
|
||||
|
||||
newpic = sprintf(FN_UPDATE_IMGURL, updates[pkgid].name);
|
||||
newpic = Updates_GetInfo(pkgid, UPDATE_PREVIEWIMAGE);
|
||||
|
||||
if not (newpic)
|
||||
return;
|
||||
|
@ -94,7 +94,6 @@ up_sbupdates_changed(int val)
|
|||
void
|
||||
menu_updates_refresh(void)
|
||||
{
|
||||
Updates_Refresh();
|
||||
int updateCount = Updates_GetPackageCount();
|
||||
|
||||
up_sbUpdates.SetMax(updateCount);
|
||||
|
@ -119,19 +118,19 @@ menu_updates_init(void)
|
|||
up_btnApply = spawn(CMainButton);
|
||||
up_btnApply.SetImage(BTN_UPDATE);
|
||||
up_btnApply.SetExecute(up_btnapply_start);
|
||||
up_btnApply.SetPos(350+96,420+30);
|
||||
up_btnApply.SetPos(50 + 160,420+13);
|
||||
Widget_Add(fn_updates, up_btnApply);
|
||||
|
||||
up_btnInstall = spawn(CMainButton);
|
||||
up_btnInstall.SetImage(BTN_INSTALL);
|
||||
up_btnInstall.SetExecute(up_btninstall_start);
|
||||
up_btnInstall.SetPos(350,420);
|
||||
up_btnInstall.SetPos(380,400);
|
||||
Widget_Add(fn_updates, up_btnInstall);
|
||||
|
||||
up_btnDelete = spawn(CMainButton);
|
||||
up_btnDelete.SetImage(BTN_DELETE);
|
||||
up_btnDelete.SetExecute(up_btnremove_start);
|
||||
up_btnDelete.SetPos(350+200,420);
|
||||
up_btnDelete.SetPos(380,400+30);
|
||||
Widget_Add(fn_updates, up_btnDelete);
|
||||
|
||||
up_frUpdates = spawn(CFrame);
|
||||
|
@ -158,59 +157,43 @@ menu_updates_init(void)
|
|||
up_frPreview.SetPos(350,160);
|
||||
up_frPreview.SetSize(256+6,128+6);
|
||||
Widget_Add(fn_updates, up_frPreview);
|
||||
|
||||
Updates_Refresh();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* Drawing */
|
||||
int g_pkgname_updating;
|
||||
void
|
||||
menu_updates_draw(void)
|
||||
{
|
||||
#ifndef WEBMENU
|
||||
static int old_enabled;
|
||||
|
||||
float fl = 0;
|
||||
|
||||
if (!g_updates_initialized) {
|
||||
int pkg_ready = 0;
|
||||
string packages = GameLibrary_GetInfo(GAMEINFO_PACKAGELIST);
|
||||
|
||||
/* we have no hard-coded list of supported packages, so query frag-net.com */
|
||||
if (!packages && !g_pkgname_updating) {
|
||||
string gamedir = GameLibrary_GetInfo(GAMEINFO_GAMEDIR);
|
||||
print(sprintf("Querying package names for %s\n", gamedir));
|
||||
uri_get(sprintf("http://www.frag-net.com/dl/packages_%s", uri_escape(gamedir)), MODSERVER_REQ_PKGNAMES);
|
||||
g_pkgname_updating = 1;
|
||||
}
|
||||
|
||||
/* don't query packages YET until we get a response */
|
||||
if (g_pkgname_updating == 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* query until 1 package is ready */
|
||||
for (int i = 0; (Updates_GetInfo(i, GPMI_NAME)); i++) {
|
||||
string installed = Updates_GetInfo(i, GPMI_INSTALLED);
|
||||
/* increment to keep track */
|
||||
if (installed == "enabled")
|
||||
old_enabled++;
|
||||
|
||||
pkg_ready = 1;
|
||||
}
|
||||
|
||||
if (pkg_ready == 1) {
|
||||
menu_updates_refresh();
|
||||
g_updates_initialized = TRUE;
|
||||
}
|
||||
/* first draw run */
|
||||
if (g_updates_initialized == 0) {
|
||||
Updates_Init();
|
||||
g_updates_initialized = 2;
|
||||
return;
|
||||
}
|
||||
|
||||
Widget_Draw(fn_updates);
|
||||
updaterStatus_t status = Updates_GetUpdaterStatus();
|
||||
|
||||
Header_Draw(HEAD_CONFIG);
|
||||
|
||||
/* we're still initializing... */
|
||||
if (g_updates_initialized == 2) {
|
||||
if (status == UPDATER_PENDING) {
|
||||
customgame_dlgWait.Draw();
|
||||
WField_Static(162, 180, "Contacting update server...", 320, 260,
|
||||
col_prompt_text, 1.0f, 2, font_label_p);
|
||||
return;
|
||||
} else if (status == UPDATER_INITIALIZED) {
|
||||
menu_updates_refresh();
|
||||
g_updates_initialized = 1;
|
||||
}
|
||||
}
|
||||
|
||||
Widget_Draw(fn_updates);
|
||||
drawpic([g_menuofs[0]+550,g_menuofs[1]+10], g_bmp[FN_LOGO],[80,80], [1,1,1], 1.0f, 0);
|
||||
|
||||
WLabel_Static(50, 143, "Data files:", 11, 11, [1,1,1],
|
||||
1.0f, 0, font_arial);
|
||||
|
||||
|
@ -231,37 +214,22 @@ menu_updates_draw(void)
|
|||
1.0f, 0, font_arial);
|
||||
|
||||
int i = up_lbUpdates.GetSelected();
|
||||
i = updates[i].uid;
|
||||
|
||||
fl = 310;
|
||||
WLabel_Static(420,fl, getpackagemanagerinfo(i, GPMI_AUTHOR), 11, 11, [1,1,1],
|
||||
WLabel_Static(420,fl, Updates_GetInfo(i, UPDATE_AUTHOR), 11, 11, [1,1,1],
|
||||
1.0f, 0, font_arial); fl += 18;
|
||||
WLabel_Static(420,fl, getpackagemanagerinfo(i, GPMI_INSTALLED), 11, 11, [1,1,1],
|
||||
WLabel_Static(420,fl, Updates_GetInfo(i, UPDATE_STATUSSTRING), 11, 11, [1,1,1],
|
||||
1.0f, 0, font_arial); fl += 18;
|
||||
WLabel_Static(420,fl, getpackagemanagerinfo(i, GPMI_LICENSE), 11, 11, [1,1,1],
|
||||
WLabel_Static(420,fl, Updates_GetInfo(i, UPDATE_LICENSE), 11, 11, [1,1,1],
|
||||
1.0f, 0, font_arial); fl += 18;
|
||||
WLabel_Static(420,fl, getpackagemanagerinfo(i, GPMI_WEBSITE), 11, 11, [1,1,1],
|
||||
WLabel_Static(420,fl, Updates_GetInfo(i, UPDATE_WEBSITE), 11, 11, [1,1,1],
|
||||
1.0f, 0, font_arial); fl += 18;
|
||||
WLabel_Static(420,fl, getpackagemanagerinfo(i, GPMI_VERSION), 11, 11, [1,1,1],
|
||||
WLabel_Static(420,fl, Updates_GetInfo(i, UPDATE_VERSION), 11, 11, [1,1,1],
|
||||
1.0f, 0, font_arial);
|
||||
|
||||
WLabel_Static(350, 143, "Preview:", 11, 11, [1,1,1],
|
||||
1.0f, 0, font_arial);
|
||||
|
||||
/* check if we've got any more packages than upon init */
|
||||
int new_packages = 0;
|
||||
for (int b = 0; (getpackagemanagerinfo(b, GPMI_NAME)); b++) {
|
||||
string installed = getpackagemanagerinfo(b, GPMI_INSTALLED);
|
||||
|
||||
/* increment to keep track */
|
||||
if (installed == "enabled")
|
||||
new_packages++;
|
||||
}
|
||||
|
||||
if (old_enabled != new_packages) {
|
||||
old_enabled = new_packages;
|
||||
localcmd("menu_restart\nmenu_updates\n");
|
||||
}
|
||||
|
||||
if (g_updates_previewpic)
|
||||
drawpic([g_menuofs[0]+350+3,g_menuofs[1]+160+3], g_updates_previewpic, [256,128], [1,1,1], 1.0f);
|
||||
#endif
|
||||
|
|
|
@ -66,6 +66,9 @@ CUpdateList::Draw(void)
|
|||
|
||||
for (int i = m_scroll; i < (visible + m_scroll); i++) {
|
||||
vector colo;
|
||||
string updateTitle = Updates_GetInfo(i, UPDATE_TITLE);
|
||||
updateState_t updateState = Updates_GetInfo(i, UPDATE_STATE);
|
||||
updateAction_t updateAction = Updates_GetInfo(i, UPDATE_ACTION);
|
||||
|
||||
if (m_selected == i) {
|
||||
colo = ML_COL_2;
|
||||
|
@ -75,60 +78,55 @@ CUpdateList::Draw(void)
|
|||
colo = ML_COL_1;
|
||||
}
|
||||
|
||||
int uid = updates[i].uid;
|
||||
string status = Updates_GetInfo(uid, GPMI_INSTALLED);
|
||||
|
||||
switch (status) {
|
||||
case "":
|
||||
if (updates[i].installed == "") {
|
||||
colo = [1,0,0];
|
||||
} else if (updates[i].installed == "pending") {
|
||||
colo = [0,1,0];
|
||||
} else if (updates[i].installed == "enabled") {
|
||||
colo = colo;
|
||||
}
|
||||
switch (updateState) {
|
||||
case UPDATESTATE_ENABLED:
|
||||
colo = ML_COL_1;
|
||||
break;
|
||||
case "pending":
|
||||
colo[0] *= 0.5;
|
||||
colo[1] *= 0.5;
|
||||
colo[2] *= 0.5;
|
||||
case UPDATESTATE_CORRUPT:
|
||||
colo = [1, 0, 0]; /* red */
|
||||
break;
|
||||
case "enabled":
|
||||
colo = colo;
|
||||
break;
|
||||
case "present":
|
||||
colo[0] *= 0.5;
|
||||
colo[1] *= 0.5;
|
||||
colo[2] *= 0.5;
|
||||
break;
|
||||
case "corrupt":
|
||||
colo = [1,0,0] * sin(time);
|
||||
break;
|
||||
default:
|
||||
float p = stof(status) / 100;
|
||||
case UPDATESTATE_PENDING:
|
||||
float p = Updates_GetInfo(i, UPDATE_DLPERCENTAGE) / 100;
|
||||
colo = [0,1,0] * p;
|
||||
drawfill([g_menuofs[0] + m_x, g_menuofs[1] + pos], [m_size[0] * p, 18],
|
||||
colo, 0.5f);
|
||||
|
||||
colo = [0.25,0.25,0.25] + ([0.75,0.75,0.75] * p);
|
||||
break;
|
||||
case UPDATESTATE_DISABLED:
|
||||
case UPDATESTATE_NONE:
|
||||
colo = [0.5, 0.5, 0.5]; /* grey */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* TODO: make this integrate with the above better */
|
||||
if (updates[i].installed == "rem") {
|
||||
if ((time*2) & 1)
|
||||
colo = [1,0,0];
|
||||
else
|
||||
colo = [0,0,0];
|
||||
} else if (updates[i].installed == "in") {
|
||||
if ((time*2) & 1)
|
||||
if ((time*2) & 1) {
|
||||
switch (updateAction) {
|
||||
case UPDATEACTION_INSTALL: /* blinking orange */
|
||||
colo = [1,1,0];
|
||||
else
|
||||
colo = [0,0,0];
|
||||
break;
|
||||
case UPDATEACTION_REINSTALL:
|
||||
colo = [0,1,0];
|
||||
break;
|
||||
case UPDATEACTION_UNINSTALL: /* blinking red */
|
||||
colo = [1,0,0];
|
||||
break;
|
||||
case UPDATEACTION_AUTOINSTALL: /* blinking orange/grey */
|
||||
colo = [0.5,0.5,0];
|
||||
break;
|
||||
case UPDATEACTION_DISABLE: /* blinking grey/color */
|
||||
colo = [0.5,0.5,0.5];
|
||||
break;
|
||||
case UPDATEACTION_RETAIN:
|
||||
case UPDATEACTION_NONE:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Game */
|
||||
WLabel_Static(m_x + 3, pos + 3, updates[i].title, 11, 11, colo,
|
||||
WLabel_Static(m_x + 3, pos + 3, updateTitle, 11, 11, colo,
|
||||
1.0f, 0, font_arial);
|
||||
|
||||
pos += 18;
|
||||
|
|
|
@ -23,4 +23,21 @@
|
|||
#include "servers.h"
|
||||
#include "tcp.h"
|
||||
#include "updates.h"
|
||||
#include "gamelibrary.h"
|
||||
#include "gamelibrary.h"
|
||||
|
||||
/** Definitions for FTE's internal package manager. We don't want you to talk to this one directly within Nuclide. */
|
||||
typedef enum
|
||||
{
|
||||
GPMI_NAME, /**< name of the package, for use with the pkg command. */
|
||||
GPMI_CATEGORY, /**< category text */
|
||||
GPMI_TITLE, /**< name of the package, for showing the user. */
|
||||
GPMI_VERSION, /**< version info (may have multiple with the same name but different versions) */
|
||||
GPMI_DESCRIPTION, /**< some blurb */
|
||||
GPMI_LICENSE, /**< what license its distributed under */
|
||||
GPMI_AUTHOR, /**< name of the person(s) who created it */
|
||||
GPMI_WEBSITE, /**< where to contribute/find out more info/etc */
|
||||
GPMI_INSTALLED, /**< current state */
|
||||
GPMI_ACTION, /**< desired state */
|
||||
GPMI_AVAILABLE, /**< whether it may be downloaded or not. */
|
||||
GPMI_FILESIZE, /**< size to download. */
|
||||
} packageType_t;
|
|
@ -61,6 +61,7 @@ float GameLibrary_InstallProgress(void);
|
|||
int GameLibrary_GetCurrentGame(void);
|
||||
/** Retrieves fields for a given game. See gameInfo_t for a list of fields you can query. */
|
||||
__variant GameLibrary_GetGameInfo(int, gameInfo_t);
|
||||
/** Retrieves fields for the currently running game. See gameInfo_t for a list of fields you can query. */
|
||||
__variant GameLibrary_GetInfo(gameInfo_t);
|
||||
|
||||
typedef enum
|
||||
|
@ -68,7 +69,8 @@ typedef enum
|
|||
GAMEINFO_NONE, /**< No gameinfo available. This is probably the engine making assumptions. */
|
||||
GAMEINFO_MANIFEST, /**< Game info was read from a manifest within the path. */
|
||||
GAMEINFO_GITXT, /**< Game info stems from a Source Engine style gameinfo.txt file. */
|
||||
GAMEINFO_LIBLIST /**< Game info stems from a GoldSrc style liblist.gam file. */
|
||||
GAMEINFO_LIBLIST, /**< Game info stems from a GoldSrc style liblist.gam file. */
|
||||
GAMEINFO_PACKAGE,
|
||||
} gi_type;
|
||||
|
||||
typedef struct
|
||||
|
|
|
@ -14,6 +14,29 @@
|
|||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* The GameLibrary concerns itself with everything around what a game is,
|
||||
how to install, activate and deactivate them. Mods are included in this,
|
||||
so I'll proceed calling them 'games' or 'custom games'.
|
||||
|
||||
A game can be installed through two primary means:
|
||||
|
||||
- Manual install, like from a .zip or some installer or archive
|
||||
- Engine package manager install, through our own user interface
|
||||
|
||||
And between these, they can come with different metadata/manifests.
|
||||
|
||||
It assumed that every game has either a FTE Manifest description,
|
||||
a gameinfo.txt (Source Engine format) or liblist.gam (GoldSrc format)
|
||||
that describes various aspects of the game. Like which version it is, what
|
||||
map will be loaded when you press 'New Game' and so on.
|
||||
|
||||
If that info is not available, some placeholder data will be used instead.
|
||||
However, games installed via the package manager will at least for the
|
||||
custom game menus not use the on-disk manifest file, but information
|
||||
provided by the package manager. Once you switch into said game everything
|
||||
within will be pulled from a file on disk, such as a liblist.gam or gameinfo.txt.
|
||||
*/
|
||||
|
||||
int g_iModInstallCache;
|
||||
string g_strModInstallCache;
|
||||
|
||||
|
@ -28,6 +51,27 @@ GameLibrary_Set(int id)
|
|||
cvar_set("com_fullgamename", games[id].game);
|
||||
}
|
||||
|
||||
static int
|
||||
GameLibrary_IDForPackageName(string packageName)
|
||||
{
|
||||
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", packageName, getpackagemanagerinfo(i, GPMI_VERSION));
|
||||
|
||||
if (name == f) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
/* no package id whatsoever */
|
||||
return (-1i);
|
||||
}
|
||||
|
||||
/** 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)
|
||||
|
@ -188,7 +232,7 @@ GameLibrary_LibListParse(int id, string strKey, string strValue)
|
|||
/* newly added with Nuclide */
|
||||
case "pkgname":
|
||||
games[id].pkgname = strValue;
|
||||
games[id].pkgid = Updates_IDForName(games[id].pkgname);
|
||||
games[id].pkgid = GameLibrary_IDForPackageName(games[id].pkgname);
|
||||
break;
|
||||
case "pkgfile":
|
||||
games[id].pkgfile = strValue;
|
||||
|
@ -391,21 +435,61 @@ GameLibrary_SetDefaults(int id, string gamedirname)
|
|||
#endif
|
||||
}
|
||||
|
||||
/** Checks if a given game directory was installed manually. */
|
||||
static bool
|
||||
GameLibrary_CheckLocalPresence(string gameDir)
|
||||
{
|
||||
string testPkgDir = __NULL__;
|
||||
bool returnSuccess = true;
|
||||
|
||||
for (int x = 0i; (testPkgDir = getgamedirinfo(x, 0)); x++) {
|
||||
if (gameDir == testPkgDir) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
GameLibrary_InitCustom(void)
|
||||
{
|
||||
int id;
|
||||
int foundself = 0;
|
||||
string gamedirname;
|
||||
string gamedirname = __NULL__;
|
||||
gameinfo_count = 0;
|
||||
int packageinfo_count = 0i;
|
||||
int c = 0i;
|
||||
|
||||
/* first count let's all manually installed mods */
|
||||
for (id = 0; (gamedirname = getgamedirinfo(id, 0)); id++) {
|
||||
gameinfo_count++;
|
||||
}
|
||||
|
||||
/* count the package installed mods after */
|
||||
for (int i = 0; (getpackagemanagerinfo(i, GPMI_NAME)); i++) {
|
||||
string packageName = getpackagemanagerinfo(i, GPMI_NAME);
|
||||
string installStatus = getpackagemanagerinfo(i, GPMI_INSTALLED);
|
||||
string prefix = substring(packageName, 0, 3);
|
||||
|
||||
/* only care about installed mods (custom games) */
|
||||
if (prefix == "cg_" && installStatus == "enabled") {
|
||||
string gameDir = substring(packageName, 3, -1);
|
||||
tokenizebyseparator(gameDir, "=");
|
||||
gameDir = argv(0);
|
||||
|
||||
/* check if this mod was installed manually already */
|
||||
if (GameLibrary_CheckLocalPresence(gameDir) == true) {
|
||||
continue;
|
||||
}
|
||||
|
||||
packageinfo_count++;
|
||||
}
|
||||
}
|
||||
|
||||
/* re-allocate the game list */
|
||||
memfree(games);
|
||||
games = memalloc(sizeof(gameinfo_t) * gameinfo_count);
|
||||
games = memalloc(sizeof(gameinfo_t) * (gameinfo_count + packageinfo_count));
|
||||
|
||||
/* The things we do for frequent flyer mileage. */
|
||||
if (!games)
|
||||
|
@ -429,8 +513,48 @@ GameLibrary_InitCustom(void)
|
|||
NSLog("[MENU] Found nothing for %s", gamedirname);
|
||||
games[id].info_type = GAMEINFO_NONE;
|
||||
}
|
||||
c = id + 1;
|
||||
}
|
||||
|
||||
/* iterate through all packages again */
|
||||
for (int i = 0i; (getpackagemanagerinfo(i, GPMI_NAME)); i++) {
|
||||
string packageName = getpackagemanagerinfo(i, GPMI_NAME);
|
||||
string installStatus = getpackagemanagerinfo(i, GPMI_INSTALLED);
|
||||
string prefix = substring(packageName, 0, 3);
|
||||
|
||||
/* same check as above in the counter */
|
||||
if (prefix == "cg_" && installStatus == "enabled") {
|
||||
string gameDir = substring(packageName, 3, -1);
|
||||
tokenizebyseparator(gameDir, "=");
|
||||
gameDir = argv(0);
|
||||
|
||||
if (GameLibrary_CheckLocalPresence(gameDir) == true) {
|
||||
continue;
|
||||
}
|
||||
|
||||
string titleString = getpackagemanagerinfo(i, GPMI_TITLE);
|
||||
string versionString = getpackagemanagerinfo(i, GPMI_VERSION);
|
||||
string authorString = getpackagemanagerinfo(i, GPMI_AUTHOR);
|
||||
string sizeString = getpackagemanagerinfo(i, GPMI_FILESIZE);
|
||||
string websiteString = getpackagemanagerinfo(i, GPMI_WEBSITE);
|
||||
|
||||
//print(sprintf("Adding packaged game %S\n", gameDir));
|
||||
GameLibrary_SetDefaults(c, gameDir);
|
||||
|
||||
games[c].game = substring(titleString, 5, -1); /* strip 'Mod: '*/
|
||||
games[c].url_info = websiteString;
|
||||
games[c].version = versionString;
|
||||
games[c].size = (int)stof(sizeString);
|
||||
games[c].type = "Both";
|
||||
games[c].info_type = GAMEINFO_PACKAGE;
|
||||
games[c].pkgname = strcat("cg_", gameDir, ";game_", gameDir, ";");
|
||||
c++;
|
||||
}
|
||||
}
|
||||
|
||||
/* now we can pretend that these weren't their own thing */
|
||||
gameinfo_count += packageinfo_count;
|
||||
|
||||
/* 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");
|
||||
|
@ -458,7 +582,6 @@ GameLibrary_Init(void)
|
|||
|
||||
/* 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;
|
||||
|
@ -521,8 +644,8 @@ GameLibrary_InstallProgress(void)
|
|||
int pkgid;
|
||||
|
||||
/* package query */
|
||||
pkgid = Updates_IDForName(argv(i));
|
||||
st = Updates_GetInfo(pkgid, GPMI_INSTALLED);
|
||||
pkgid = GameLibrary_IDForPackageName(argv(i));
|
||||
st = getpackagemanagerinfo(pkgid, GPMI_INSTALLED);
|
||||
|
||||
/* filter out statuses so we can calculate percentage */
|
||||
switch (st) {
|
||||
|
@ -555,10 +678,11 @@ 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));
|
||||
int pkgid = GameLibrary_IDForPackageName(argv(i));
|
||||
localcmd(sprintf("pkg add %s\n", argv(i)));
|
||||
print(sprintf("Marking package %s for install.\n",
|
||||
argv(i)));
|
||||
|
@ -575,7 +699,12 @@ GameLibrary_Install(int gameID)
|
|||
{
|
||||
string st;
|
||||
|
||||
st = Updates_GetInfo(games[gameID].pkgid, GPMI_INSTALLED);
|
||||
if (gameID >= gameinfo_count || gameID < 0i) {
|
||||
print(sprintf("GameLibrary_Install: Invalid game id %i!\n", gameID));
|
||||
return;
|
||||
}
|
||||
|
||||
st = getpackagemanagerinfo(games[gameID].pkgid, GPMI_INSTALLED);
|
||||
|
||||
print(st);
|
||||
print("\n");
|
||||
|
@ -593,6 +722,11 @@ GameLibrary_Install(int gameID)
|
|||
void
|
||||
GameLibrary_Activate(int gameID)
|
||||
{
|
||||
if (gameID >= gameinfo_count || gameID < 0i) {
|
||||
print(sprintf("GameLibrary_Activate: Invalid game id %i!\n", gameID));
|
||||
return;
|
||||
}
|
||||
|
||||
GameLibrary_Set(gameID);
|
||||
|
||||
if (games[gameID].info_type == GAMEINFO_MANIFEST)
|
||||
|
@ -636,10 +770,14 @@ GameLibrary_GetInfo(gameInfo_t infoType)
|
|||
return GameLibrary_GetGameInfo(gameinfo_current, infoType);
|
||||
}
|
||||
|
||||
/** Retrieves info for a given game. */
|
||||
__variant
|
||||
GameLibrary_GetGameInfo(int gameID, gameInfo_t infoType)
|
||||
{
|
||||
if (gameID >= gameinfo_count || gameID < 0i) {
|
||||
print(sprintf("GameLibrary_GetGameInfo: Invalid game id %i!\n", gameID));
|
||||
return __NULL__;
|
||||
}
|
||||
|
||||
switch (infoType) {
|
||||
case GAMEINFO_TITLE:
|
||||
return (string)games[gameID].game;
|
||||
|
|
|
@ -15,6 +15,28 @@
|
|||
*/
|
||||
|
||||
#ifndef WEBMENU
|
||||
/* the same as GameLibrary_IDForPackageName */
|
||||
static int
|
||||
ModServer_IDForPackageName(string packageName)
|
||||
{
|
||||
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", packageName, getpackagemanagerinfo(i, GPMI_VERSION));
|
||||
|
||||
if (name == f) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
/* no package id whatsoever */
|
||||
return (-1i);
|
||||
}
|
||||
|
||||
void*
|
||||
memrealloc(__variant *oldptr, int elementsize, int old_num, int new_num)
|
||||
{
|
||||
|
@ -161,7 +183,7 @@ ModServer_ParseItem(string data)
|
|||
break;
|
||||
case "gameinfo_pkgname":
|
||||
games[id].pkgname = argv(i+1);
|
||||
games[id].pkgid = Updates_IDForName(games[id].pkgname);
|
||||
games[id].pkgid = ModServer_IDForPackageName(games[id].pkgname);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -169,6 +191,8 @@ ModServer_ParseItem(string data)
|
|||
}
|
||||
}
|
||||
|
||||
void Updater_URI_Callback(float id, float code, string data, int resourcebytes);
|
||||
|
||||
/* Called as an eventual result of the uri_get builtin. */
|
||||
void
|
||||
ModServer_URI_Callback(float id, float code, string data, int resourcebytes)
|
||||
|
@ -202,8 +226,7 @@ ModServer_URI_Callback(float id, float code, string data, int resourcebytes)
|
|||
ModServer_ParseItem(data);
|
||||
break;
|
||||
case MODSERVER_REQ_PKGNAMES:
|
||||
games[GameLibrary_GetCurrentGame()].pkgname = data;
|
||||
g_pkgname_updating = 0;
|
||||
Updater_URI_Callback(id, code, data, resourcebytes);
|
||||
break;
|
||||
default:
|
||||
print(sprintf("^1ModServer_URI_Callback^7: Unknown request id %d with code %d\n", id, code));
|
||||
|
|
|
@ -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
|
||||
|
@ -14,54 +14,75 @@
|
|||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
string(float id, float b) getgamedirinfo = #0;
|
||||
string(int packageidx, int desiredfield) getpackagemanagerinfo = #0;
|
||||
|
||||
/** Different types you can pass to `Updates_GetInfo(...)` to learn details about a given Update entry. */
|
||||
typedef enum
|
||||
{
|
||||
GPMI_NAME, /**< name of the package, for use with the pkg command. */
|
||||
GPMI_CATEGORY, /**< category text */
|
||||
GPMI_TITLE, /**< name of the package, for showing the user. */
|
||||
GPMI_VERSION, /**< version info (may have multiple with the same name but different versions) */
|
||||
GPMI_DESCRIPTION, /**< some blurb */
|
||||
GPMI_LICENSE, /**< what license its distributed under */
|
||||
GPMI_AUTHOR, /**< name of the person(s) who created it */
|
||||
GPMI_WEBSITE, /**< where to contribute/find out more info/etc */
|
||||
GPMI_INSTALLED, /**< current state */
|
||||
GPMI_ACTION, /**< desired state */
|
||||
GPMI_AVAILABLE, /**< whether it may be downloaded or not. */
|
||||
GPMI_FILESIZE, /**< size to download. */
|
||||
UPDATE_NAME, /**< (string) name of the package, for use with the pkg command. */
|
||||
UPDATE_CATEGORY, /**< (string) category text */
|
||||
UPDATE_TITLE, /**< (string) name of the package, for showing the user. */
|
||||
UPDATE_VERSION, /**< (string) version info (may have multiple with the same name but different versions) */
|
||||
UPDATE_DESCRIPTION, /**< (string) some blurb */
|
||||
UPDATE_LICENSE, /**< (string) what license its distributed under */
|
||||
UPDATE_AUTHOR, /**< (string) name of the person(s) who created it */
|
||||
UPDATE_WEBSITE, /**< (string) where to contribute/find out more info/etc */
|
||||
UPDATE_STATE, /**< (updateState_t) The current state of the update. */
|
||||
UPDATE_ACTION, /**< (updateAction_t) Pending action of the update. */
|
||||
UPDATE_FILESIZE, /**< (int) size to download in bytes. */
|
||||
UPDATE_PREVIEWIMAGE, /**< (string) Path to a preview image in 4:3 aspect ratio. */
|
||||
UPDATE_STATUSSTRING, /**< (string) Localizable string that gives you the update status. */
|
||||
UPDATE_DLPERCENTAGE, /**< (float) Download progress in percent (0-100). */
|
||||
} updateType_t;
|
||||
|
||||
typedef struct
|
||||
/** Return values from passing UPDATE_STATE to Updates_GetInfo() */
|
||||
typedef enum
|
||||
{
|
||||
string name;
|
||||
string category;
|
||||
string title;
|
||||
string version;
|
||||
string description;
|
||||
string license;
|
||||
string author;
|
||||
string website;
|
||||
string installed;
|
||||
int size;
|
||||
int uid;
|
||||
} update_t;
|
||||
UPDATESTATE_NONE, /**< Update is not installed, or unavailable. */
|
||||
UPDATESTATE_DISABLED, /**< Update is installed, but disabled. */
|
||||
UPDATESTATE_ENABLED, /**< Update is installed and enabled. */
|
||||
UPDATESTATE_CORRUPT, /**< Update on disk is corrupted. */
|
||||
UPDATESTATE_PENDING /**< Update is pending a change. Usually when we're downloading it. */
|
||||
} updateState_t;
|
||||
|
||||
int g_platform_update_count;
|
||||
update_t *updates;
|
||||
/** Return values from passing UPDATE_ACTION to Updates_GetInfo() */
|
||||
typedef enum
|
||||
{
|
||||
UPDATEACTION_NONE, /**< Update is not marked for any change. */
|
||||
UPDATEACTION_INSTALL, /**< Update marked for installation. */
|
||||
UPDATEACTION_REINSTALL, /**< Update marked as needing re-installation. */
|
||||
UPDATEACTION_UNINSTALL, /**< Update marked for removal. */
|
||||
UPDATEACTION_AUTOINSTALL, /**< Update marked as needing to be installed, due to a dependency. */
|
||||
UPDATEACTION_DISABLE, /**< Update has been marked for disabling. */
|
||||
UPDATEACTION_RETAIN /**< Update has been marked as being retained. */
|
||||
} updateAction_t;
|
||||
|
||||
#define FN_UPDATE_IMGURL "http://www.frag-net.com/dl/img/%s.jpg"
|
||||
/** These are the possible return values from Updates_GetUpdaterStatus().
|
||||
That way you can put up a loading screen for when the updater is still initiliazing,
|
||||
or be notified of when an updater is not available at all. */
|
||||
typedef enum
|
||||
{
|
||||
UPDATER_NONE, /**< Nuclide's updater has not been initialized. You need to call Update_Init(). */
|
||||
UPDATER_UNAVAILABLE, /**< Nuclide's updater is unavailable. This may be due to the update server being offline. */
|
||||
UPDATER_PENDING, /**< Nuclide's updater is pending. May change to UNAVAILABLE or INITIALIZED. */
|
||||
UPDATER_INITIALIZED /**< Nuclide's updater is initialized and may have entries. Use Updates_GetUpdateCount() to query how many. */
|
||||
} updaterStatus_t;
|
||||
|
||||
/** Call this in order to contact the update server and fill the list of updates. */
|
||||
void Updates_Init(void);
|
||||
void Updates_Refresh(void);
|
||||
/** Retrieve the status of the updater. See updaterStatus_t for valid return values. */
|
||||
updaterStatus_t Updates_GetUpdaterStatus(void);
|
||||
/** Returns the total amount of updates available for the currently running game. */
|
||||
int Updates_GetPackageCount(void);
|
||||
int Updates_IDForName(string);
|
||||
string Updates_NameForID(int);
|
||||
string Updates_GetInfo(int, updateType_t);
|
||||
/** Query a package (by ID) for its various info fields. See updateType_t for available fields. */
|
||||
__variant Updates_GetInfo(int, updateType_t);
|
||||
/** Returns if our current game has updates available for any installed packages. */
|
||||
bool Updates_Available(void);
|
||||
|
||||
/** Toggle the installation/disabling of an update. May return true/false if it succeeded in marking the package. */
|
||||
bool Updates_Toggle(int);
|
||||
/** Mark an update as pending installion. May return true/false if it succeeded in marking the package. */
|
||||
bool Updates_Install(int);
|
||||
/** Mark an update as pending deletion. May return true/false if it succeeded in marking the package. */
|
||||
bool Updates_Remove(int);
|
||||
/** Mark an update as pending uninstallation. May return true/false if it succeeded in marking the package. */
|
||||
bool Updates_Destroy(int);
|
||||
/** Apply all pending changes to packages. May return true/false if it succeeded in doing so. */
|
||||
bool Updates_ApplyPendingChanges(void);
|
|
@ -1,13 +1,72 @@
|
|||
/** needs to be called upon menu-init, and call Updates_Refresh() if auto-updates
|
||||
are enabled. if a chooser does not want updates, then we won't. */
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
string name;
|
||||
string category;
|
||||
string title;
|
||||
string version;
|
||||
string description;
|
||||
string license;
|
||||
string author;
|
||||
string website;
|
||||
string installed;
|
||||
updateState_t state;
|
||||
updateAction_t pending_action;
|
||||
int size;
|
||||
int uid;
|
||||
string preview_image;
|
||||
float dlpercentage;
|
||||
} update_t;
|
||||
|
||||
string(float id, float b) getgamedirinfo = #0;
|
||||
string(int packageidx, int desiredfield) getpackagemanagerinfo = #0;
|
||||
|
||||
#define FN_UPDATE_IMGURL "http://www.frag-net.com/dl/img/%s.jpg"
|
||||
int g_platform_update_count;
|
||||
update_t *updates;
|
||||
|
||||
var updaterStatus_t updater_package_status = UPDATER_NONE;
|
||||
|
||||
void
|
||||
Updates_Init(void)
|
||||
{
|
||||
/*localcmd("pkg addsource https://www.frag-net.com/pkgs/list\n");*/
|
||||
print("Update system initialized.\n");
|
||||
string packages;
|
||||
|
||||
/* first, see if our game info sets any packages. */
|
||||
packages = GameLibrary_GetInfo(GAMEINFO_PACKAGELIST);
|
||||
|
||||
/* we have no hard-coded list of supported packages, so query frag-net.com */
|
||||
if (!packages) {
|
||||
string gamedir = cvar_string("fs_game");
|
||||
print(sprintf("Querying package names for %s\n", gamedir));
|
||||
uri_get(sprintf("http://www.frag-net.com/dl/packages_%s", uri_escape(gamedir)), MODSERVER_REQ_PKGNAMES);
|
||||
updater_package_status = UPDATER_PENDING;
|
||||
} else {
|
||||
updater_package_status = UPDATER_INITIALIZED;
|
||||
}
|
||||
}
|
||||
|
||||
updaterStatus_t
|
||||
Updates_GetUpdaterStatus(void)
|
||||
{
|
||||
return updater_package_status;
|
||||
}
|
||||
|
||||
/** will return a cached value */
|
||||
int
|
||||
Updates_GetPackageCount(void)
|
||||
{
|
||||
|
@ -43,8 +102,68 @@ Updates_IsRecommended(string packageName)
|
|||
return false;
|
||||
}
|
||||
|
||||
/** called whenever we need to re-initialize the updates struct */
|
||||
void
|
||||
static void
|
||||
Updates_RefreshStateValues(int packageID)
|
||||
{
|
||||
int pkgUID = updates[packageID].uid;
|
||||
string installedState = getpackagemanagerinfo(pkgUID, GPMI_INSTALLED);
|
||||
string actionState = getpackagemanagerinfo(pkgUID, GPMI_ACTION);
|
||||
|
||||
switch (actionState) {
|
||||
case "user":
|
||||
updates[packageID].pending_action = UPDATEACTION_INSTALL;
|
||||
break;
|
||||
case "reinstall":
|
||||
updates[packageID].pending_action = UPDATEACTION_REINSTALL;
|
||||
break;
|
||||
case "purge":
|
||||
updates[packageID].pending_action = UPDATEACTION_UNINSTALL;
|
||||
break;
|
||||
case "auto":
|
||||
updates[packageID].pending_action = UPDATEACTION_AUTOINSTALL;
|
||||
break;
|
||||
case "disable":
|
||||
updates[packageID].pending_action = UPDATEACTION_DISABLE;
|
||||
break;
|
||||
case "retain":
|
||||
/*updates[packageID].pending_action = UPDATEACTION_RETAIN;
|
||||
break;*/
|
||||
default:
|
||||
updates[packageID].pending_action = UPDATEACTION_NONE;
|
||||
}
|
||||
|
||||
switch (installedState) {
|
||||
case "present":
|
||||
updates[packageID].state = UPDATESTATE_DISABLED;
|
||||
break;
|
||||
case "enabled":
|
||||
updates[packageID].state = UPDATESTATE_ENABLED;
|
||||
break;
|
||||
case "corrupt":
|
||||
updates[packageID].state = UPDATESTATE_CORRUPT;
|
||||
break;
|
||||
case "pending":
|
||||
updates[packageID].state = UPDATESTATE_PENDING;
|
||||
break;
|
||||
default:
|
||||
updates[packageID].state = UPDATESTATE_NONE;
|
||||
}
|
||||
|
||||
updates[packageID].dlpercentage = stof(installedState);
|
||||
|
||||
/* HACK: the engine doesn't seem to set pending while installing, so let us do the job then */
|
||||
if (updates[packageID].dlpercentage > 0)
|
||||
updates[packageID].state = UPDATESTATE_PENDING;
|
||||
|
||||
/* HACK: enabled AND pending installation? smells like an engine bug! */
|
||||
if (updates[packageID].state == UPDATESTATE_ENABLED) {
|
||||
if (updates[packageID].pending_action == UPDATEACTION_INSTALL) {
|
||||
updates[packageID].pending_action = UPDATEACTION_NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
Updates_Refresh(void)
|
||||
{
|
||||
int c = 0i;
|
||||
|
@ -56,7 +175,7 @@ Updates_Refresh(void)
|
|||
}
|
||||
|
||||
/* count all updates that we've got in our package sources */
|
||||
for (int i = 0i; (Updates_GetInfo(i, GPMI_NAME)); i++) {
|
||||
for (int i = 0i; (getpackagemanagerinfo(i, GPMI_NAME)); i++) {
|
||||
g_platform_update_count++;
|
||||
}
|
||||
|
||||
|
@ -67,21 +186,23 @@ Updates_Refresh(void)
|
|||
int id = i;
|
||||
|
||||
/* skip not recommended packages */
|
||||
if (Updates_IsRecommended(Updates_GetInfo(id, GPMI_NAME)) == false)
|
||||
if (Updates_IsRecommended(getpackagemanagerinfo(id, GPMI_NAME)) == false)
|
||||
continue;
|
||||
|
||||
updates[c].name = Updates_GetInfo(id, GPMI_NAME);
|
||||
updates[c].category = Updates_GetInfo(id, GPMI_CATEGORY);
|
||||
updates[c].title = Updates_GetInfo(id, GPMI_TITLE);
|
||||
updates[c].version = Updates_GetInfo(id, GPMI_VERSION);
|
||||
updates[c].description = Updates_GetInfo(id, GPMI_DESCRIPTION);
|
||||
updates[c].license = Updates_GetInfo(id, GPMI_LICENSE);
|
||||
updates[c].author = Updates_GetInfo(id, GPMI_AUTHOR);
|
||||
updates[c].website = Updates_GetInfo(id, GPMI_WEBSITE);
|
||||
updates[c].installed = Updates_GetInfo(id, GPMI_INSTALLED);
|
||||
updates[c].size = (int)stof(Updates_GetInfo(id, GPMI_FILESIZE));
|
||||
updates[c].name = getpackagemanagerinfo(id, GPMI_NAME);
|
||||
updates[c].category = getpackagemanagerinfo(id, GPMI_CATEGORY);
|
||||
updates[c].title = getpackagemanagerinfo(id, GPMI_TITLE);
|
||||
updates[c].version = getpackagemanagerinfo(id, GPMI_VERSION);
|
||||
updates[c].description = getpackagemanagerinfo(id, GPMI_DESCRIPTION);
|
||||
updates[c].license = getpackagemanagerinfo(id, GPMI_LICENSE);
|
||||
updates[c].author = getpackagemanagerinfo(id, GPMI_AUTHOR);
|
||||
updates[c].website = getpackagemanagerinfo(id, GPMI_WEBSITE);
|
||||
|
||||
updates[c].size = (int)stof(getpackagemanagerinfo(id, GPMI_FILESIZE));
|
||||
updates[c].uid = i;
|
||||
precache_pic(sprintf(FN_UPDATE_IMGURL, updates[c].name));
|
||||
updates[c].preview_image = sprintf(FN_UPDATE_IMGURL, updates[c].name);
|
||||
Updates_RefreshStateValues(c);
|
||||
|
||||
c++;
|
||||
}
|
||||
|
||||
|
@ -89,94 +210,177 @@ Updates_Refresh(void)
|
|||
g_platform_update_count = c;
|
||||
}
|
||||
|
||||
/** Returns the package ID for a given name. Will return -1 when not available. */
|
||||
int
|
||||
Updates_IDForName(string packageName)
|
||||
{
|
||||
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", packageName, getpackagemanagerinfo(i, GPMI_VERSION));
|
||||
|
||||
if (name == f) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
/* no package id whatsoever */
|
||||
return (-1i);
|
||||
}
|
||||
|
||||
/** Returns the package name for a given ID. Returns __NULL__ when not available. */
|
||||
string
|
||||
Updates_NameForID(int packageID)
|
||||
{
|
||||
string packageName = getpackagemanagerinfo(packageID, GPMI_NAME);
|
||||
|
||||
if not (packageName)
|
||||
return __NULL__;
|
||||
|
||||
return packageName;
|
||||
}
|
||||
|
||||
/** Query a package (by ID) for its various info fields. See updateType_t for available fields. */
|
||||
string
|
||||
__variant
|
||||
Updates_GetInfo(int packageID, updateType_t fieldType)
|
||||
{
|
||||
return getpackagemanagerinfo(packageID, (int)fieldType);
|
||||
if (packageID >= g_platform_update_count || packageID < 0i) {
|
||||
print(sprintf("Updates_GetInfo: Invalid package id %i!\n", packageID));
|
||||
return __NULL__;
|
||||
}
|
||||
|
||||
Updates_RefreshStateValues(packageID);
|
||||
|
||||
switch (fieldType) {
|
||||
case UPDATE_NAME:
|
||||
return (string)updates[packageID].name;
|
||||
break;
|
||||
case UPDATE_CATEGORY:
|
||||
return (string)updates[packageID].category;
|
||||
break;
|
||||
case UPDATE_TITLE:
|
||||
return (string)updates[packageID].title;
|
||||
break;
|
||||
case UPDATE_VERSION:
|
||||
return (string)updates[packageID].version;
|
||||
break;
|
||||
case UPDATE_DESCRIPTION:
|
||||
return (string)updates[packageID].description;
|
||||
break;
|
||||
case UPDATE_LICENSE:
|
||||
return (string)updates[packageID].license;
|
||||
break;
|
||||
case UPDATE_AUTHOR:
|
||||
return (string)updates[packageID].author;
|
||||
break;
|
||||
case UPDATE_WEBSITE:
|
||||
return (string)updates[packageID].website;
|
||||
break;
|
||||
case UPDATE_STATE:
|
||||
return (updateState_t)updates[packageID].state;
|
||||
break;
|
||||
case UPDATE_ACTION:
|
||||
return (updateAction_t)updates[packageID].pending_action;
|
||||
break;
|
||||
case UPDATE_FILESIZE:
|
||||
return (int)updates[packageID].size;
|
||||
break;
|
||||
case UPDATE_PREVIEWIMAGE:
|
||||
return (string)updates[packageID].preview_image;
|
||||
break;
|
||||
case UPDATE_STATUSSTRING:
|
||||
/* if we have a action, focus on that */
|
||||
switch (updates[packageID].pending_action) {
|
||||
case UPDATEACTION_INSTALL:
|
||||
if (updates[packageID].dlpercentage > 0.0) {
|
||||
return sprintf("%d %%", updates[packageID].dlpercentage);
|
||||
} else {
|
||||
return _("UPDATE_PENDING_INSTALL");
|
||||
}
|
||||
break;
|
||||
case UPDATEACTION_REINSTALL:
|
||||
return _("UPDATE_PENDING_REINSTALL");
|
||||
break;
|
||||
case UPDATEACTION_UNINSTALL:
|
||||
return _("UPDATE_PENDING_UNINSTALL");
|
||||
break;
|
||||
case UPDATEACTION_AUTOINSTALL:
|
||||
return _("UPDATE_PENDING_AUTOINSTALL");
|
||||
break;
|
||||
case UPDATEACTION_DISABLE:
|
||||
return _("UPDATE_PENDING_DISABLE");
|
||||
break;
|
||||
case UPDATEACTION_RETAIN:
|
||||
return _("UPDATE_PENDING_RETAIN");
|
||||
break;
|
||||
default:
|
||||
switch (updates[packageID].state) {
|
||||
case UPDATESTATE_DISABLED:
|
||||
return _("UPDATE_DISABLED");
|
||||
break;
|
||||
case UPDATESTATE_ENABLED:
|
||||
return _("UPDATE_ENABLED");
|
||||
break;
|
||||
case UPDATESTATE_CORRUPT:
|
||||
return _("UPDATE_CORRUPT");
|
||||
break;
|
||||
default:
|
||||
return _("UPDATE_NOTINSTALLED");
|
||||
}
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case UPDATE_DLPERCENTAGE:
|
||||
return updates[packageID].dlpercentage;
|
||||
break;
|
||||
default:
|
||||
return __NULL__;
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns if our current game has updates available for any installed packages. */
|
||||
bool
|
||||
Updates_Available(void)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Toggle the installation of a package. Will return true if it was done. */
|
||||
bool
|
||||
Updates_Toggle(int packageID)
|
||||
{
|
||||
switch (updates[packageID].installed) {
|
||||
case "":
|
||||
case "rem":
|
||||
if (packageID >= g_platform_update_count || packageID < 0i) {
|
||||
print(sprintf("Updates_Toggle: Invalid package id %i!\n", packageID));
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (updates[packageID].pending_action) {
|
||||
case UPDATEACTION_INSTALL:
|
||||
case UPDATEACTION_REINSTALL:
|
||||
localcmd(sprintf("pkg rem %s\n", updates[packageID].name));
|
||||
break;
|
||||
case UPDATEACTION_UNINSTALL:
|
||||
case UPDATEACTION_DISABLE:
|
||||
localcmd(sprintf("pkg add %s\n", updates[packageID].name));
|
||||
updates[packageID].installed = "pending";
|
||||
break;
|
||||
default:
|
||||
localcmd(sprintf("pkg rem %s\n", updates[packageID].name));
|
||||
updates[packageID].installed = "rem";
|
||||
if (updates[packageID].state == UPDATESTATE_ENABLED) {
|
||||
localcmd(sprintf("pkg rem %s\n", updates[packageID].name));
|
||||
} else {
|
||||
localcmd(sprintf("pkg add %s\n", updates[packageID].name));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Mark a package as pending installion. May return true/false if it succeeded in marking the package. */
|
||||
bool
|
||||
Updates_Install(int packageID)
|
||||
{
|
||||
if (packageID >= g_platform_update_count || packageID < 0i) {
|
||||
print(sprintf("Updates_Install: Invalid package id %i!\n", packageID));
|
||||
return false;
|
||||
}
|
||||
|
||||
localcmd(sprintf("pkg add %s\n", updates[packageID].name));
|
||||
updates[packageID].installed = "pending";
|
||||
print(sprintf("Marking package %s for install.\n", updates[packageID].title));
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Mark a package as pending deletion. May return true/false if it succeeded in marking the package. */
|
||||
bool
|
||||
Updates_Remove(int packageID)
|
||||
{
|
||||
if (packageID >= g_platform_update_count || packageID < 0i) {
|
||||
print(sprintf("Updates_Remove: Invalid package id %i!\n", packageID));
|
||||
return false;
|
||||
}
|
||||
|
||||
localcmd(sprintf("pkg rem %s\n", updates[packageID].name));
|
||||
updates[packageID].installed = "rem";
|
||||
print(sprintf("Marking package %s for 'removal'.\n", updates[packageID].title));
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Apply all pending changes to packages. May return true/false if it succeeded in doing so. */
|
||||
bool
|
||||
Updates_Destroy(int packageID)
|
||||
{
|
||||
if (packageID >= g_platform_update_count || packageID < 0i) {
|
||||
print(sprintf("Updates_Destroy: Invalid package id %i!\n", packageID));
|
||||
return false;
|
||||
}
|
||||
|
||||
localcmd(sprintf("pkg del %s\n", updates[packageID].name));
|
||||
print(sprintf("Marking package %s for 'deletion'.\n", updates[packageID].title));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Updates_ApplyPendingChanges(void)
|
||||
{
|
||||
|
@ -184,4 +388,20 @@ Updates_ApplyPendingChanges(void)
|
|||
localcmd("pkg apply\n");
|
||||
print("Applying package changes.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Updater_URI_Callback(float id, float code, string data, int resourcebytes)
|
||||
{
|
||||
if (code == 404) {
|
||||
string gameDir = cvar_string("fs_game");
|
||||
games[GameLibrary_GetCurrentGame()].pkgname = strcat("cg_", gameDir, ";game_", gameDir, ";");
|
||||
|
||||
} else {
|
||||
print(sprintf("URI: %d %d %S %i\n", id, code, data, resourcebytes));
|
||||
games[GameLibrary_GetCurrentGame()].pkgname = data;
|
||||
}
|
||||
|
||||
updater_package_status = UPDATER_INITIALIZED;
|
||||
Updates_Refresh();
|
||||
}
|
Loading…
Reference in a new issue