Parse meta information from drag+dropped/file-associated packages for easier installation of mods.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5934 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
parent
248c248ece
commit
1614b75142
7 changed files with 266 additions and 75 deletions
|
@ -5369,6 +5369,7 @@ typedef struct {
|
|||
struct dl_download *dl;
|
||||
vfsfile_t *srcfile;
|
||||
vfsfile_t *dstfile;
|
||||
char *packageinfo;
|
||||
unsigned int flags;
|
||||
char fname[1]; //system path or url.
|
||||
} hrf_t;
|
||||
|
@ -5621,6 +5622,7 @@ void Host_DoRunFile(hrf_t *f)
|
|||
char loadcommand[MAX_OSPATH];
|
||||
qboolean isnew = false;
|
||||
qboolean haschanged = false;
|
||||
enum fs_relative qroot = FS_GAME;
|
||||
|
||||
if (f->flags & HRF_WAITING)
|
||||
{
|
||||
|
@ -5634,6 +5636,8 @@ done:
|
|||
if (f->flags & HRF_WAITING)
|
||||
waitingformanifest--;
|
||||
|
||||
if (f->packageinfo)
|
||||
Z_Free(f->packageinfo);
|
||||
if (f->srcfile)
|
||||
VFS_CLOSE(f->srcfile);
|
||||
if (f->dstfile)
|
||||
|
@ -5862,13 +5866,17 @@ done:
|
|||
goto done;
|
||||
}
|
||||
|
||||
if (f->flags & HRF_MANIFEST)
|
||||
if (f->flags & HRF_PACKAGE)
|
||||
{
|
||||
Z_Free(f->packageinfo);
|
||||
f->packageinfo = PM_GeneratePackageFromMeta(f->srcfile, qname,sizeof(qname), &qroot);
|
||||
}
|
||||
else if (f->flags & HRF_MANIFEST)
|
||||
{
|
||||
Host_DoRunFile(f);
|
||||
return;
|
||||
}
|
||||
|
||||
if (f->flags & HRF_QTVINFO)
|
||||
else if (f->flags & HRF_QTVINFO)
|
||||
{
|
||||
//pass the file object to the qtv code instead of trying to install it.
|
||||
CL_ParseQTVDescriptor(f->srcfile, f->fname);
|
||||
|
@ -5879,7 +5887,11 @@ done:
|
|||
|
||||
VFS_SEEK(f->srcfile, 0);
|
||||
|
||||
f->dstfile = FS_OpenVFS(qname, "rb", FS_GAME);
|
||||
if (f->flags & HRF_OVERWRITE)
|
||||
;//haschanged = isnew = true;
|
||||
else
|
||||
{
|
||||
f->dstfile = FS_OpenVFS(qname, "rb", (qroot==FS_GAMEONLY)?FS_GAME:qroot);
|
||||
if (f->dstfile)
|
||||
{
|
||||
//do a real diff.
|
||||
|
@ -5904,31 +5916,32 @@ done:
|
|||
}
|
||||
else
|
||||
isnew = true;
|
||||
}
|
||||
|
||||
if (haschanged)
|
||||
{
|
||||
if (!(f->flags & HRF_ACTION))
|
||||
{
|
||||
Key_Dest_Remove(kdm_console);
|
||||
if (haschanged)
|
||||
{
|
||||
Menu_Prompt(Host_RunFilePrompted, f, va("File already exists.\nWhat would you like to do?\n%s\n", displayname), "Overwrite", "Run old", "Cancel");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (isnew)
|
||||
{
|
||||
if (!(f->flags & HRF_ACTION))
|
||||
{
|
||||
Key_Dest_Remove(kdm_console);
|
||||
Menu_Prompt(Host_RunFilePrompted, f, va("File appears new.\nWould you like to install\n%s\n", displayname), "Install!", "", "Cancel");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Menu_Prompt(NULL, NULL, va("File is already installed\n%s\n", displayname), NULL, NULL, "Cancel");
|
||||
f->flags |= HRF_ABORT;
|
||||
}
|
||||
|
||||
if (f->flags & HRF_OVERWRITE)
|
||||
}
|
||||
else if (f->flags & HRF_OVERWRITE)
|
||||
{
|
||||
char buffer[8192];
|
||||
int len;
|
||||
f->dstfile = FS_OpenVFS(qname, "wb", FS_GAMEONLY);
|
||||
f->dstfile = FS_OpenVFS(qname, "wb", qroot);
|
||||
if (f->dstfile)
|
||||
{
|
||||
#ifdef FTE_TARGET_WEB
|
||||
|
@ -5943,16 +5956,18 @@ done:
|
|||
break;
|
||||
VFS_WRITE(f->dstfile, buffer, len);
|
||||
}
|
||||
|
||||
VFS_CLOSE(f->dstfile);
|
||||
f->dstfile = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (f->flags & HRF_PACKAGE)
|
||||
PM_FileInstalled(COM_SkipPath(f->fname), qroot, f->packageinfo, true);
|
||||
|
||||
Cbuf_AddText(loadcommand, RESTRICT_LOCAL);
|
||||
}
|
||||
|
||||
f->flags |= HRF_ABORT;
|
||||
Host_DoRunFile(f);
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
|
||||
//only valid once the host has been initialised, as it needs a working filesystem.
|
||||
|
|
|
@ -22,6 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include "quakedef.h"
|
||||
#include "cl_ignore.h"
|
||||
#include "shader.h"
|
||||
#include "fs.h"
|
||||
|
||||
void CL_GetNumberedEntityInfo (int num, float *org, float *ang);
|
||||
void CLDP_ParseDarkPlaces5Entities(void);
|
||||
|
@ -2563,6 +2564,8 @@ void DL_Abort(qdownload_t *dl, enum qdlabort aborttype)
|
|||
Con_Printf("Couldn't rename %s to %s\n", nativetmp, nativefinal);
|
||||
}
|
||||
}
|
||||
|
||||
PM_FileInstalled(dl->localname, dl->fsroot, NULL, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -129,7 +129,7 @@ typedef struct package_s {
|
|||
|
||||
char *mirror[MAXMIRRORS]; //FIXME: move to two types of dep...
|
||||
char gamedir[16];
|
||||
enum fs_relative fsroot;
|
||||
enum fs_relative fsroot; //FS_BINARYPATH or FS_ROOT _ONLY_
|
||||
char version[16];
|
||||
char *arch;
|
||||
char *qhash;
|
||||
|
@ -321,6 +321,24 @@ static void PM_AddDep(package_t *p, int deptype, const char *depname)
|
|||
nd->next = *link;
|
||||
*link = nd;
|
||||
}
|
||||
static const char *PM_GetDepSingle(package_t *p, int deptype)
|
||||
{
|
||||
struct packagedep_s *d;
|
||||
const char *val = NULL;
|
||||
|
||||
//no dupes.
|
||||
for (d = p->deps; d ; d = d->next)
|
||||
{
|
||||
if (d->dtype == deptype)
|
||||
{
|
||||
if (val)
|
||||
return NULL; //found a second. give up in confusion.
|
||||
else
|
||||
val = d->name; //found the first, but continue to make sure there's no second.
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
||||
static qboolean PM_HasDep(package_t *p, int deptype, const char *depname)
|
||||
{
|
||||
struct packagedep_s *d;
|
||||
|
@ -934,7 +952,7 @@ struct packagesourceinfo_s
|
|||
char mirror[MAXMIRRORS][MAX_OSPATH];
|
||||
int nummirrors;
|
||||
};
|
||||
static const char *PM_ParsePackage(struct packagesourceinfo_s *source, const char *tokstart, int wantvariation)
|
||||
static const char *PM_ParsePackage(struct packagesourceinfo_s *source, const char *tokstart, package_t **outpackage, int wantvariation)
|
||||
{
|
||||
package_t *p;
|
||||
struct packagedep_s *dep;
|
||||
|
@ -1279,17 +1297,22 @@ static const char *PM_ParsePackage(struct packagesourceinfo_s *source, const cha
|
|||
if (source->url)
|
||||
PM_AddDep(p, DEP_SOURCE, source->url);
|
||||
|
||||
if (outpackage)
|
||||
*outpackage = p;
|
||||
else
|
||||
{
|
||||
PM_InsertPackage(p);
|
||||
|
||||
if (wantvariation == 0) //only the first!
|
||||
{
|
||||
while (++wantvariation < variation)
|
||||
if (tokstart != PM_ParsePackage(source, start, wantvariation))
|
||||
if (tokstart != PM_ParsePackage(source, start, NULL, wantvariation))
|
||||
{
|
||||
Con_Printf(CON_ERROR"%s: Unable to parse package variation...\n", source->url);
|
||||
break; //erk?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tokstart;
|
||||
}
|
||||
|
@ -1524,13 +1547,13 @@ static qboolean PM_ParsePackageList(const char *f, unsigned int parseflags, cons
|
|||
if (!strcmp(com_token, "{"))
|
||||
{
|
||||
linestart = COM_StringParse (linestart, com_token, sizeof(com_token), false, false);
|
||||
f = PM_ParsePackage(&source, linestart, 0);
|
||||
f = PM_ParsePackage(&source, linestart, NULL, 0);
|
||||
if (!f)
|
||||
break; //erk!
|
||||
}
|
||||
else if (source.version < 3)
|
||||
{ //old single-line gibberish
|
||||
PM_ParsePackage(&source, tokstart, -1);
|
||||
PM_ParsePackage(&source, tokstart, NULL, -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1567,6 +1590,149 @@ void PM_EnumeratePlugins(void (*callback)(const char *name))
|
|||
}
|
||||
#endif
|
||||
|
||||
static qboolean QDECL Host_StubClose (struct vfsfile_s *file)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
static char *PM_GetMetaTextFromFile(vfsfile_t *file, char *filename, char *qhash, size_t hashsize) //seeks, but does not close.
|
||||
{
|
||||
qboolean (QDECL *OriginalClose) (struct vfsfile_s *file) = file->Close; //evilness
|
||||
searchpathfuncs_t *archive;
|
||||
char *ret = NULL, *line;
|
||||
*qhash = 0;
|
||||
|
||||
file->Close = Host_StubClose; //so it doesn't go away without our say
|
||||
archive = FS_OpenPackByExtension(file, NULL, filename, filename);
|
||||
if (archive)
|
||||
{
|
||||
flocation_t loc;
|
||||
vfsfile_t *metafile = NULL;
|
||||
if (archive->FindFile(archive, &loc, "fte.meta", NULL))
|
||||
metafile = archive->OpenVFS(archive, &loc, "rb");
|
||||
if (metafile)
|
||||
{
|
||||
size_t sz = VFS_GETLEN(metafile);
|
||||
ret = BZ_Malloc(sz+1);
|
||||
VFS_READ(metafile, ret, sz);
|
||||
ret[sz] = 0;
|
||||
VFS_CLOSE(metafile);
|
||||
}
|
||||
|
||||
//get the archive's qhash.
|
||||
Q_snprintfz(qhash, hashsize, "0x%x", archive->GeneratePureCRC(archive, 0, 0));
|
||||
|
||||
line = ret;
|
||||
do
|
||||
{
|
||||
line = (char*)Cmd_TokenizeString (line, false, false);
|
||||
if (!strcmp(com_token, "{"))
|
||||
break; //okay, found the start of it.
|
||||
} while (*line);
|
||||
//and leave it pointing there for easier parsing later. single package only.
|
||||
line = va("qhash %s\n%s", qhash, line);
|
||||
line = Z_StrDup(line);
|
||||
Z_Free(ret);
|
||||
ret = line;
|
||||
|
||||
archive->ClosePath(archive);
|
||||
}
|
||||
file->Close = OriginalClose;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *PM_GeneratePackageFromMeta(vfsfile_t *file, char *fname, size_t fnamesize, enum fs_relative *fsroot)
|
||||
{
|
||||
package_t *p = NULL;
|
||||
char pkgname[MAX_QPATH];
|
||||
char qhash[64];
|
||||
char *pkgdata = PM_GetMetaTextFromFile(file, fname, qhash, sizeof(qhash));
|
||||
|
||||
struct packagesourceinfo_s pkgsrc = {DPF_ENABLED};
|
||||
pkgsrc.version = 3;
|
||||
pkgsrc.categoryprefix = "";
|
||||
|
||||
COM_StripAllExtensions(COM_SkipPath(fname), pkgname,sizeof(pkgname));
|
||||
|
||||
PM_PreparePackageList(); //just in case.
|
||||
|
||||
//see if we can make any sense of it.
|
||||
PM_ParsePackage(&pkgsrc, pkgdata, &p, 1);
|
||||
if (p)
|
||||
{
|
||||
if (p->extract == EXTRACT_COPY)
|
||||
{
|
||||
const char *f = PM_GetDepSingle(p, DEP_FILE);
|
||||
if (!f)
|
||||
f = va("%s", fname); //erk?
|
||||
|
||||
if (*p->gamedir)
|
||||
f = va("%s/%s", p->gamedir, f);
|
||||
|
||||
Z_StrDupPtr(&p->qhash, qhash);
|
||||
if (PM_TryGenCachedName(f, p, fname, fnamesize))
|
||||
;
|
||||
else
|
||||
Q_strncpyz(fname, f, fnamesize);
|
||||
*fsroot = p->fsroot;
|
||||
}
|
||||
|
||||
//okay, seems there's something in it.
|
||||
PM_FreePackage(p);
|
||||
}
|
||||
|
||||
return pkgdata;
|
||||
}
|
||||
|
||||
static qboolean PM_FileInstalled_Internal(const char *package, const char *category, const char *title, const char *filename, enum fs_relative fsroot, unsigned pkgflags, void *metainfo, qboolean enable)
|
||||
{
|
||||
package_t *p;
|
||||
|
||||
if (metainfo)
|
||||
{
|
||||
struct packagesourceinfo_s pkgsrc = {DPF_ENABLED};
|
||||
pkgsrc.version = 3;
|
||||
pkgsrc.categoryprefix = "";
|
||||
|
||||
PM_ParsePackage(&pkgsrc, metainfo, &p, 1);
|
||||
if (!p)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
p = Z_Malloc(sizeof(*p));
|
||||
p->priority = PM_DEFAULTPRIORITY;
|
||||
p->fsroot = fsroot;
|
||||
strcpy(p->version, "?" "?" "?" "?");
|
||||
}
|
||||
|
||||
p->deps = Z_Malloc(sizeof(*p->deps) + strlen(filename));
|
||||
p->deps->dtype = DEP_FILE;
|
||||
strcpy(p->deps->name, filename);
|
||||
|
||||
if (pkgflags&DPF_PLUGIN)
|
||||
p->arch = Z_StrDup(THISARCH);
|
||||
if (!p->name)
|
||||
p->name = Z_StrDup(package);
|
||||
if (!p->title)
|
||||
p->title = Z_StrDup(title);
|
||||
if (!p->category && !*p->category)
|
||||
p->category = Z_StrDup(category);
|
||||
p->flags = pkgflags|DPF_NATIVE|DPF_FORGETONUNINSTALL;
|
||||
if (enable)
|
||||
p->flags |= DPF_USERMARKED|DPF_ENABLED;
|
||||
|
||||
if (PM_InsertPackage(p))
|
||||
PM_WriteInstalledPackages();
|
||||
|
||||
return true;
|
||||
}
|
||||
void PM_FileInstalled(const char *filename, enum fs_relative fsroot, void *metainfo, qboolean enable)
|
||||
{
|
||||
char pkgname[MAX_QPATH];
|
||||
COM_StripAllExtensions(COM_SkipPath(filename), pkgname,sizeof(pkgname));
|
||||
PM_FileInstalled_Internal(pkgname, "", pkgname, filename, fsroot, DPF_GUESSED, metainfo, enable);
|
||||
}
|
||||
|
||||
#ifdef PLUGINS
|
||||
static package_t *PM_FindExactPackage(const char *packagename, const char *arch, const char *version, unsigned int flags);
|
||||
static package_t *PM_FindPackage(const char *packagename);
|
||||
|
@ -1583,7 +1749,6 @@ static int QDECL PM_EnumeratedPlugin (const char *name, qofs_t size, time_t mtim
|
|||
char vmname[MAX_QPATH];
|
||||
int len, l, a;
|
||||
char *dot;
|
||||
const char *synthver = "??""??";
|
||||
char *pkgname;
|
||||
if (!strncmp(name, PLUGINPREFIX, strlen(PLUGINPREFIX)))
|
||||
Q_strncpyz(vmname, name+strlen(PLUGINPREFIX), sizeof(vmname));
|
||||
|
@ -1637,26 +1802,13 @@ static int QDECL PM_EnumeratedPlugin (const char *name, qofs_t size, time_t mtim
|
|||
return true; //don't include it if its a dupe anyway.
|
||||
//FIXME: should be checking whether there's a package that provides the file...
|
||||
|
||||
p = Z_Malloc(sizeof(*p));
|
||||
p->deps = Z_Malloc(sizeof(*p->deps) + strlen(name));
|
||||
p->deps->dtype = DEP_FILE;
|
||||
strcpy(p->deps->name, name);
|
||||
p->arch = Z_StrDup(THISARCH);
|
||||
p->name = Z_StrDup(pkgname);
|
||||
p->title = Z_StrDup(vmname);
|
||||
p->category = Z_StrDup("Plugins/");
|
||||
p->priority = PM_DEFAULTPRIORITY;
|
||||
p->fsroot = FS_BINARYPATH;
|
||||
strcpy(p->version, synthver);
|
||||
p->flags = DPF_PLUGIN|DPF_NATIVE|DPF_FORGETONUNINSTALL;
|
||||
return PM_FileInstalled_Internal(pkgname, "Plugins/", vmname, name, FS_BINARYPATH, DPF_PLUGIN, NULL,
|
||||
#ifdef ENABLEPLUGINSBYDEFAULT
|
||||
p->flags |= DPF_USERMARKED|DPF_ENABLED;
|
||||
true
|
||||
#else
|
||||
*(int*)param = true;
|
||||
false
|
||||
#endif
|
||||
PM_InsertPackage(p);
|
||||
|
||||
return true;
|
||||
);
|
||||
}
|
||||
#ifndef SERVERONLY
|
||||
#ifndef ENABLEPLUGINSBYDEFAULT
|
||||
|
@ -1674,8 +1826,8 @@ static void PM_PluginDetected(void *ctx, int status)
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef SERVERONLY
|
||||
void PM_AutoUpdateQuery(void *ctx, promptbutton_t status)
|
||||
/*#ifndef SERVERONLY
|
||||
static void PM_AutoUpdateQuery(void *ctx, promptbutton_t status)
|
||||
{
|
||||
if (status == PROMPT_CANCEL)
|
||||
return; //'Later'
|
||||
|
@ -1683,7 +1835,7 @@ void PM_AutoUpdateQuery(void *ctx, promptbutton_t status)
|
|||
Cmd_ExecuteString("menu_download\n", RESTRICT_LOCAL);
|
||||
Menu_Download_Update();
|
||||
}
|
||||
#endif
|
||||
#endif*/
|
||||
|
||||
static void PM_PreparePackageList(void)
|
||||
{
|
||||
|
@ -3943,7 +4095,23 @@ void PM_Command_f(void)
|
|||
{
|
||||
if ((pm_source[i].flags & SRCFL_HISTORIC) && !developer.ival)
|
||||
continue; //hidden ones were historically enabled/disabled. remember the state even when using a different fmf, but don't confuse the user.
|
||||
Con_Printf("%s %s\n", pm_source[i].url, pm_source[i].flags?"(explicit)":"(implicit)");
|
||||
|
||||
if (pm_source[i].flags & SRCFL_ENABLED)
|
||||
Con_Printf("^&02 ");
|
||||
else if (pm_source[i].flags & SRCFL_DISABLED)
|
||||
Con_Printf("^&04 ");
|
||||
else
|
||||
Con_Printf("^&0E ");
|
||||
|
||||
if (pm_source[i].flags & SRCFL_DISABLED)
|
||||
Con_Printf("%s ", pm_source[i].url); //enable
|
||||
else
|
||||
Con_Printf("%s ", pm_source[i].url); //disable
|
||||
|
||||
if (pm_source[i].flags & SRCFL_USER)
|
||||
Con_Printf("- ^[[Delete]\\type\\pkg remsource \"%s\"^]\n", pm_source[i].url);
|
||||
else
|
||||
Con_Printf("(implicit)\n");
|
||||
c++;
|
||||
}
|
||||
Con_Printf("<%u sources>\n", (unsigned)c);
|
||||
|
|
|
@ -73,6 +73,8 @@ void FS_UnRegisterFileSystemModule(void *module);
|
|||
|
||||
void FS_AddHashedPackage(searchpath_t **oldpaths, const char *parent_pure, const char *parent_logical, searchpath_t *search, unsigned int loadstuff, const char *pakpath, const char *qhash, const char *pakprefix, unsigned int packageflags);
|
||||
void PM_LoadPackages(searchpath_t **oldpaths, const char *parent_pure, const char *parent_logical, searchpath_t *search, unsigned int loadstuff, int minpri, int maxpri);
|
||||
void *PM_GeneratePackageFromMeta(vfsfile_t *file, char *fname, size_t fnamesize, enum fs_relative *fsroot);
|
||||
void PM_FileInstalled(const char *filename, enum fs_relative fsroot, void *metainfo, qboolean enable); //we finished installing a file via some other mechanism (drag+drop or from server. insert it into the updates menu.
|
||||
void PM_EnumeratePlugins(void (*callback)(const char *name));
|
||||
int PM_IsApplying(qboolean listsonly);
|
||||
unsigned int PM_MarkUpdates (void); //mark new/updated packages as needing install.
|
||||
|
|
|
@ -1467,6 +1467,7 @@ void Matrix4x4_CM_Projection_Far(float *proj, float fovx, float fovy, float near
|
|||
|
||||
void Matrix4x4_CM_Projection_Inf(float *proj, float fovx, float fovy, float neard, qboolean d3d)
|
||||
{
|
||||
//FIXME: glDepthRange(1,0) for reverse-z (with cull flipped). combine with arb_clip_control for 0-1. this should give much better depth precision with floating point depth buffers.
|
||||
float xmin, xmax, ymin, ymax;
|
||||
double dn = (d3d?0:-1), df = 1;
|
||||
|
||||
|
|
|
@ -118,6 +118,8 @@ typedef struct q2trace_s
|
|||
//19
|
||||
#define FL_HUBSAVERESET (1<<20) //hexen2, ent is reverted to original state on map changes.
|
||||
#define FL_CLASS_DEPENDENT (1<<21) //hexen2
|
||||
//22
|
||||
//23
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue