1
0
Fork 0
forked from fte/fteqw

------------------------------------------------------------------------

r4207 | acceptthis | 2013-02-16 23:16:07 +0000 (Sat, 16 Feb 2013) | 2 lines

update np plugin to do autoupdates properly.
Stop people from being able to save the game while dead (in single player, at least).
------------------------------------------------------------------------


git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4205 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2013-03-12 22:58:13 +00:00
parent 165a9006c7
commit 3717f655a3
4 changed files with 316 additions and 18 deletions

View file

@ -5,7 +5,7 @@
static void UnpackAndExtractPakFiles_Complete(struct dl_download *dl); static void UnpackAndExtractPakFiles_Complete(struct dl_download *dl);
static void pscript_property_splash_sets(struct context *ctx, const char *val); static void pscript_property_splash_sets(struct context *ctx, const char *val);
void *globalmutex;
#ifdef _MSC_VER #ifdef _MSC_VER
# ifdef _WIN64 # ifdef _WIN64
@ -254,11 +254,19 @@ dblbreak:
if (addrfamily) if (addrfamily)
*addrfamily = ((struct sockaddr*)sadr)->sa_family; *addrfamily = ((struct sockaddr*)sadr)->sa_family;
if (addrsize)
{
if (((struct sockaddr*)sadr)->sa_family == AF_INET) if (((struct sockaddr*)sadr)->sa_family == AF_INET)
{
if (!((struct sockaddr_in *)sadr)->sin_port)
((struct sockaddr_in *)sadr)->sin_port = htons(defaultport);
if (addrsize)
*addrsize = sizeof(struct sockaddr_in); *addrsize = sizeof(struct sockaddr_in);
}
else else
{
if (!((struct sockaddr_in6 *)sadr)->sin6_port)
((struct sockaddr_in6 *)sadr)->sin6_port = htons(defaultport);
if (addrsize)
*addrsize = sizeof(struct sockaddr_in6); *addrsize = sizeof(struct sockaddr_in6);
} }
@ -443,6 +451,187 @@ vfsfile_t *VFSPIPE_Open(void)
#if defined(OFFICIAL_RELEASE)
#define BUILDTYPE "rel"
#else
#define BUILDTYPE "test"
#define UPDATE_URL "http://triptohell.info/moodles/"
#define UPDATE_URL_VERSION UPDATE_URL "version.txt"
#ifdef _WIN64
#define UPDATE_URL_BUILD UPDATE_URL "win64/fte" EXETYPE ".exe"
#else
#define UPDATE_URL_BUILD UPDATE_URL "win32/fte" EXETYPE ".exe"
#endif
#endif
//#if defined(GLQUAKE) && defined(D3DQUAKE)
// #define EXETYPE "qw"
//#elif defined(GLQUAKE)
// #ifdef MINIMAL
// #define EXETYPE "minglqw"
// #else
#define EXETYPE "glqw"
// #endif
//#elif defined(D3DQUAKE)
// #define EXETYPE "d3dqw"
//#elif defined(SWQUAKE)
// #define EXETYPE "swqw"
//#else //erm...
// #define EXETYPE "qw"
//#endif
qboolean MyRegGetStringValue(HKEY base, char *keyname, char *valuename, void *data, int datalen)
{
qboolean result = false;
DWORD resultlen = datalen - 1;
HKEY subkey;
DWORD type = REG_NONE;
if (RegOpenKeyEx(base, keyname, 0, KEY_READ, &subkey) == ERROR_SUCCESS)
{
result = ERROR_SUCCESS == RegQueryValueEx(subkey, valuename, NULL, &type, data, &datalen);
RegCloseKey (subkey);
}
if (type == REG_SZ || type == REG_EXPAND_SZ)
((char*)data)[datalen] = 0;
else
((char*)data)[0] = 0;
return result;
}
void MyRegSetValue(HKEY base, char *keyname, char *valuename, int type, void *data, int datalen)
{
HKEY subkey;
if (RegCreateKeyEx(base, keyname, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &subkey, NULL) == ERROR_SUCCESS)
{
RegSetValueEx(subkey, valuename, 0, type, data, datalen);
RegCloseKey (subkey);
}
}
void MyRegDeleteKeyValue(HKEY base, char *keyname, char *valuename)
{
HKEY subkey;
if (RegOpenKeyEx(base, keyname, 0, KEY_WRITE, &subkey) == ERROR_SUCCESS)
{
RegDeleteValue(subkey, valuename);
RegCloseKey (subkey);
}
}
qboolean Update_GetHomeDirectory(char *homedir, int homedirsize)
{
HMODULE shfolder = LoadLibrary("shfolder.dll");
if (shfolder)
{
HRESULT (WINAPI *dSHGetFolderPath) (HWND hwndOwner, int nFolder, HANDLE hToken, DWORD dwFlags, LPTSTR pszPath);
dSHGetFolderPath = (void *)GetProcAddress(shfolder, "SHGetFolderPathA");
if (dSHGetFolderPath)
{
char folder[MAX_PATH];
// 0x5 == CSIDL_PERSONAL
if (dSHGetFolderPath(NULL, 0x5, NULL, 0, folder) == S_OK)
{
Q_snprintfz(homedir, homedirsize, "%s/My Games/%s/", folder, FULLENGINENAME);
return true;
}
}
// FreeLibrary(shfolder);
}
return false;
}
#include "fs.h"
struct dl_download *enginedownloadactive;
void Update_Version_Updated(struct dl_download *dl)
{
//happens in a thread, avoid va
if (dl->file)
{
if (dl->status == DL_FINISHED)
{
char buf[8192];
unsigned int size = 0, chunk, fullsize;
char pendingname[MAX_OSPATH];
FILE *pending;
Update_GetHomeDirectory(pendingname, sizeof(pendingname));
Q_strncatz(pendingname, DISTRIBUTION BUILDTYPE EXETYPE".tmp", sizeof(pendingname));
fullsize = VFS_GETLEN(dl->file);
pending = fopen(pendingname, "wb");
if (pending)
{
while(1)
{
chunk = VFS_READ(dl->file, buf, sizeof(buf));
if (!chunk)
break;
size += fwrite(buf, 1, chunk, pending);
}
fclose(pending);
if (fullsize == size)
{
MyRegSetValue(HKEY_CURRENT_USER, "Software\\"FULLENGINENAME, "pending" BUILDTYPE EXETYPE, REG_SZ, pendingname, strlen(pendingname)+1);
}
else
{
dl->status = DL_FAILED;
}
}
}
VFS_CLOSE(dl->file);
dl->file = NULL;
}
}
qboolean Plug_GetDownloadedName(char *updatedpath, int updatedpathlen)
{
char pendingpath[MAX_OSPATH];
char temppath[MAX_OSPATH];
Sys_LockMutex(globalmutex);
if (!enginedownloadactive || (enginedownloadactive->status == DL_FINISHED || enginedownloadactive->status == DL_FAILED))
{
if (enginedownloadactive)
DL_Close(enginedownloadactive);
enginedownloadactive = NULL;
/*if there's some downloaded binary which isn't running yet, kill the old active one and update it*/
MyRegGetStringValue(HKEY_CURRENT_USER, "Software\\"FULLENGINENAME, "pending" BUILDTYPE EXETYPE, pendingpath, sizeof(pendingpath));
if (*pendingpath)
{
MyRegDeleteKeyValue(HKEY_CURRENT_USER, "Software\\"FULLENGINENAME, "pending" BUILDTYPE EXETYPE);
Update_GetHomeDirectory(temppath, sizeof(temppath));
CreateDirectory(temppath, NULL);
Q_strncatz(temppath, "cur" BUILDTYPE EXETYPE".exe", sizeof(temppath));
DeleteFile(temppath);
if (MoveFile(pendingpath, temppath))
MyRegSetValue(HKEY_CURRENT_USER, "Software\\"FULLENGINENAME, BUILDTYPE EXETYPE, REG_SZ, temppath, strlen(temppath)+1);
}
/*grab the binary to run from the registry*/
MyRegGetStringValue(HKEY_CURRENT_USER, "Software\\"FULLENGINENAME, BUILDTYPE EXETYPE, updatedpath, updatedpathlen);
if (!*updatedpath)
{
/*ooer, its not set, try and download one. updates are handled by the client itself.*/
enginedownloadactive = DL_Create(UPDATE_URL_BUILD);
if (enginedownloadactive)
{
enginedownloadactive->user_ctx = NULL;
DL_CreateThread(enginedownloadactive, VFSPIPE_Open(), Update_Version_Updated);
}
}
}
Sys_UnlockMutex(globalmutex);
return !!*updatedpath;
}
@ -564,7 +753,7 @@ char *cleanarg(char *arg)
return strdup("\"\""); return strdup("\"\"");
} }
void Plug_GetBinaryName(char *exe, int exelen, qboolean Plug_GetBinaryName(char *exe, int exelen,
char *basedir, int basedirlen) char *basedir, int basedirlen)
{ {
char buffer[1024]; char buffer[1024];
@ -572,6 +761,10 @@ void Plug_GetBinaryName(char *exe, int exelen,
char value[1024]; char value[1024];
FILE *f; FILE *f;
Q_snprintfz(buffer, sizeof(buffer), "%s%s", binarypath, "npfte.txt"); Q_snprintfz(buffer, sizeof(buffer), "%s%s", binarypath, "npfte.txt");
*exe = 0;
*basedir = 0;
f = fopen(buffer, "rt"); f = fopen(buffer, "rt");
if (f) if (f)
{ {
@ -581,7 +774,7 @@ void Plug_GetBinaryName(char *exe, int exelen,
*value = 0; *value = 0;
COM_ParseOut(COM_ParseOut(buffer, cmd, sizeof(cmd)), value, sizeof(value)); COM_ParseOut(COM_ParseOut(buffer, cmd, sizeof(cmd)), value, sizeof(value));
if (!strcmp(cmd, "relexe")) if (!strcmp(cmd, "relexe"))
Q_snprintfz(buffer, sizeof(buffer), "%s%s", binarypath, value); Q_snprintfz(exe, exelen, "%s%s", binarypath, value);
else if (!strcmp(cmd, "absexe")) else if (!strcmp(cmd, "absexe"))
Q_strncpyz(exe, value, exelen); Q_strncpyz(exe, value, exelen);
else if (!strcmp(cmd, "basedir")) else if (!strcmp(cmd, "basedir"))
@ -589,6 +782,10 @@ void Plug_GetBinaryName(char *exe, int exelen,
} }
fclose(f); fclose(f);
} }
if (!*exe)
return Plug_GetDownloadedName(exe, exelen);
return false;
} }
int Plug_GenCommandline(struct context *ctx, char **argv, int maxargs) int Plug_GenCommandline(struct context *ctx, char **argv, int maxargs)
@ -598,15 +795,24 @@ int Plug_GenCommandline(struct context *ctx, char **argv, int maxargs)
char tok[256]; char tok[256];
char exe[1024]; char exe[1024];
char basedir[1024]; char basedir[1024];
qboolean autoupdate;
Q_snprintfz(exe, sizeof(exe), "%s%s", binarypath, "fteqw"); Q_snprintfz(exe, sizeof(exe), "%s%s", binarypath, "fteqw");
*basedir = 0; *basedir = 0;
Plug_GetBinaryName(exe, sizeof(exe), basedir, sizeof(basedir)); autoupdate = Plug_GetBinaryName(exe, sizeof(exe), basedir, sizeof(basedir));
if (!*exe)
return 0; //error
argv[0] = strdup(exe); argv[0] = strdup(exe);
argc = 1; argc = 1;
if (autoupdate)
{
ADDRARG("-autoupdate");
}
ADDRARG("-plugin"); ADDRARG("-plugin");
if (*basedir) if (*basedir)
@ -682,6 +888,8 @@ qboolean Plug_GenCommandlineString(struct context *ctx, char *cmdline, int cmdli
char *argv[64]; char *argv[64];
int argc, i; int argc, i;
argc = Plug_GenCommandline(ctx, argv, 64); argc = Plug_GenCommandline(ctx, argv, 64);
if (!argc)
return false;
for (i = 0; i < argc; i++) for (i = 0; i < argc; i++)
{ {
//add quotes for any arguments with spaces //add quotes for any arguments with spaces
@ -712,14 +920,14 @@ void Plug_ExecuteCommand(struct context *ctx, char *message, ...)
WriteFile(ctx->pipetoengine, finalmessage, strlen(finalmessage), &written, NULL); WriteFile(ctx->pipetoengine, finalmessage, strlen(finalmessage), &written, NULL);
} }
void Plug_CreatePluginProcess(struct context *ctx) qboolean Plug_CreatePluginProcess(struct context *ctx)
{ {
char cmdline[8192]; char cmdline[8192];
PROCESS_INFORMATION childinfo; PROCESS_INFORMATION childinfo;
STARTUPINFO startinfo; STARTUPINFO startinfo;
SECURITY_ATTRIBUTES pipesec = {sizeof(pipesec), NULL, TRUE}; SECURITY_ATTRIBUTES pipesec = {sizeof(pipesec), NULL, TRUE};
if (!Plug_GenCommandlineString(ctx, cmdline, sizeof(cmdline))) if (!Plug_GenCommandlineString(ctx, cmdline, sizeof(cmdline)))
return; return false;
memset(&startinfo, 0, sizeof(startinfo)); memset(&startinfo, 0, sizeof(startinfo));
startinfo.cb = sizeof(startinfo); startinfo.cb = sizeof(startinfo);
@ -742,6 +950,8 @@ void Plug_CreatePluginProcess(struct context *ctx)
//these ends of the pipes were inherited by now, so we can discard them in the caller. //these ends of the pipes were inherited by now, so we can discard them in the caller.
CloseHandle(startinfo.hStdOutput); CloseHandle(startinfo.hStdOutput);
CloseHandle(startinfo.hStdInput); CloseHandle(startinfo.hStdInput);
return true;
} }
int Plug_PluginThread(void *ctxptr) int Plug_PluginThread(void *ctxptr)
@ -820,11 +1030,80 @@ int Plug_PluginThread(void *ctxptr)
} }
#endif #endif
Plug_CreatePluginProcess(ctx); if (!Plug_CreatePluginProcess(ctx))
{
if (!enginedownloadactive)
{
strcpy(ctx->pub.statusmessage, "Unable to determine engine to run. Plugin is not correctly installed.");
if (ctx->bfuncs.StatusChanged)
ctx->bfuncs.StatusChanged(ctx->hostinstance);
ctx->pub.running = false;
}
else
{
int os = -1;
while(1)
{
Sys_LockMutex(globalmutex);
if (!enginedownloadactive)
{
Sys_UnlockMutex(globalmutex);
if (!Plug_CreatePluginProcess(ctx))
ctx->pub.running = false;
break;
}
if (os != enginedownloadactive->status)
{
os = enginedownloadactive->status;
switch(os)
{
case DL_PENDING:
strcpy(ctx->pub.statusmessage, "Download pending.");
break;
case DL_FAILED:
strcpy(ctx->pub.statusmessage, "Engine download failed. Try later, or fix internet connection.");
os = -2; //stop trying.
ctx->pub.running = false;
break;
case DL_RESOLVING:
strcpy(ctx->pub.statusmessage, "Download pending. Resolving hostname.");
break;
case DL_QUERY:
strcpy(ctx->pub.statusmessage, "Download pending. Reqeusting file.");
break;
case DL_ACTIVE:
Q_snprintfz(ctx->pub.statusmessage, sizeof(ctx->pub.statusmessage), "Download pending. At %u of %u.", enginedownloadactive->completed, enginedownloadactive->totalsize);
os = -1; //keep refreshing
break;
case DL_FINISHED:
strcpy(ctx->pub.statusmessage, "Download completed!");
DL_Close(enginedownloadactive);
enginedownloadactive = NULL;
break;
}
Sys_UnlockMutex(globalmutex);
if (ctx->bfuncs.StatusChanged)
ctx->bfuncs.StatusChanged(ctx->hostinstance);
}
else
Sys_UnlockMutex(globalmutex);
if (os == -2)
break;
Sleep(1000);
}
}
}
if (ctx->bfuncs.StatusChanged) if (ctx->bfuncs.StatusChanged)
ctx->bfuncs.StatusChanged(ctx->hostinstance); ctx->bfuncs.StatusChanged(ctx->hostinstance);
if (ctx->pub.running)
while(1) while(1)
{ {
DWORD avail; DWORD avail;
@ -837,6 +1116,7 @@ int Plug_PluginThread(void *ctxptr)
if (!ReadFile(ctx->pipefromengine, buffer + bufoffs, avail, &avail, NULL) || !avail) if (!ReadFile(ctx->pipefromengine, buffer + bufoffs, avail, &avail, NULL) || !avail)
{ {
//broken pipe, client died. //broken pipe, client died.
*ctx->pub.statusmessage = 0;
break; break;
} }
bufoffs += avail; bufoffs += avail;
@ -887,13 +1167,12 @@ int Plug_PluginThread(void *ctxptr)
break; break;
} }
} }
ctx->pub.running = false;
*ctx->pub.statusmessage = 0;
if (ctx->bfuncs.StatusChanged) if (ctx->bfuncs.StatusChanged)
ctx->bfuncs.StatusChanged(ctx->hostinstance); ctx->bfuncs.StatusChanged(ctx->hostinstance);
if (ctx == activecontext) if (ctx == activecontext)
activecontext = NULL; activecontext = NULL;
ctx->pub.running = false;
return 0; return 0;
} }
@ -1652,6 +1931,8 @@ static const struct plugfuncs exportedplugfuncs_1 =
const struct plugfuncs *Plug_GetFuncs(int ver) const struct plugfuncs *Plug_GetFuncs(int ver)
{ {
if (!globalmutex)
globalmutex = Sys_CreateMutex();
if (ver == 1) if (ver == 1)
return &exportedplugfuncs_1; return &exportedplugfuncs_1;
else else

View file

@ -2024,7 +2024,7 @@ qboolean MyRegGetStringValue(HKEY base, char *keyname, char *valuename, void *da
DWORD resultlen = datalen - 1; DWORD resultlen = datalen - 1;
HKEY subkey; HKEY subkey;
DWORD type = REG_NONE; DWORD type = REG_NONE;
if (RegOpenKeyEx(base, keyname, 0, KEY_WRITE, &subkey) == ERROR_SUCCESS) if (RegOpenKeyEx(base, keyname, 0, KEY_READ, &subkey) == ERROR_SUCCESS)
{ {
result = ERROR_SUCCESS == RegQueryValueEx(subkey, valuename, NULL, &type, data, &datalen); result = ERROR_SUCCESS == RegQueryValueEx(subkey, valuename, NULL, &type, data, &datalen);
RegCloseKey (subkey); RegCloseKey (subkey);
@ -2167,18 +2167,25 @@ qboolean Sys_CheckUpdated(void)
return false; return false;
else if (!COM_CheckParm("-autoupdate") && !COM_CheckParm("--autoupdate")) else if (!COM_CheckParm("-autoupdate") && !COM_CheckParm("--autoupdate"))
return false; return false;
else if (COM_CheckParm("-plugin"))
{
//download, but don't invoke. the caller is expected to start us up properly (once installed).
}
else if (!ffe) else if (!ffe)
{ {
//if we're not from the frontend, we should run the updated build instead
char frontendpath[MAX_OSPATH]; char frontendpath[MAX_OSPATH];
char pendingpath[MAX_OSPATH]; char pendingpath[MAX_OSPATH];
char updatedpath[MAX_QPATH]; char updatedpath[MAX_OSPATH];
MyRegGetStringValue(HKEY_CURRENT_USER, "Software\\"FULLENGINENAME, "pending" BUILDTYPE EXETYPE, pendingpath, sizeof(pendingpath)); MyRegGetStringValue(HKEY_CURRENT_USER, "Software\\"FULLENGINENAME, "pending" BUILDTYPE EXETYPE, pendingpath, sizeof(pendingpath));
if (*pendingpath) if (*pendingpath)
{ {
MyRegDeleteKeyValue(HKEY_CURRENT_USER, "Software\\"FULLENGINENAME, "pending" BUILDTYPE EXETYPE); MyRegDeleteKeyValue(HKEY_CURRENT_USER, "Software\\"FULLENGINENAME, "pending" BUILDTYPE EXETYPE);
Update_GetHomeDirectory(updatedpath, sizeof(updatedpath)); Update_GetHomeDirectory(updatedpath, sizeof(updatedpath));
CreateDirectory(updatedpath, NULL);
Q_strncatz(updatedpath, "cur" BUILDTYPE EXETYPE".exe", sizeof(updatedpath)); Q_strncatz(updatedpath, "cur" BUILDTYPE EXETYPE".exe", sizeof(updatedpath));
DeleteFile(updatedpath);
if (MoveFile(pendingpath, updatedpath)) if (MoveFile(pendingpath, updatedpath))
MyRegSetValue(HKEY_CURRENT_USER, "Software\\"FULLENGINENAME, BUILDTYPE EXETYPE, REG_SZ, updatedpath, strlen(updatedpath)+1); MyRegSetValue(HKEY_CURRENT_USER, "Software\\"FULLENGINENAME, BUILDTYPE EXETYPE, REG_SZ, updatedpath, strlen(updatedpath)+1);
} }

View file

@ -28,8 +28,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,3 FILEVERSION 1,0,2,0
PRODUCTVERSION 1,0,0,3 PRODUCTVERSION 1,0,2,0
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -48,7 +48,7 @@ BEGIN
VALUE "CompanyName", "Forethought Entertainment\0" VALUE "CompanyName", "Forethought Entertainment\0"
VALUE "FileDescription", "Quake in a browser\0" VALUE "FileDescription", "Quake in a browser\0"
VALUE "FileExtents", "qtv|mvd\0" VALUE "FileExtents", "qtv|mvd\0"
VALUE "FileVersion", "1, 0, 0, 3\0" VALUE "FileVersion", "1, 0, 2, 0\0"
VALUE "InternalName", "npfte\0" VALUE "InternalName", "npfte\0"
VALUE "LegalCopyright", "Copyright © 2010\0" VALUE "LegalCopyright", "Copyright © 2010\0"
VALUE "LegalTrademarks", "\0" VALUE "LegalTrademarks", "\0"
@ -56,7 +56,7 @@ BEGIN
VALUE "OriginalFilename", "npfte.dll\0" VALUE "OriginalFilename", "npfte.dll\0"
VALUE "PrivateBuild", "\0" VALUE "PrivateBuild", "\0"
VALUE "ProductName", "FTE Browser Plugin\0" VALUE "ProductName", "FTE Browser Plugin\0"
VALUE "ProductVersion", "1, 0, 0, 3\0" VALUE "ProductVersion", "1, 0, 2, 0\0"
VALUE "SpecialBuild", "\0" VALUE "SpecialBuild", "\0"
END END
END END

View file

@ -989,6 +989,16 @@ void SV_Savegame (char *savename)
return; return;
} }
if (sv.allocated_client_slots == 1 && svs.gametype == GT_PROGS)
{
if (svs.clients->state > cs_connected && svs.clients[0].edict->v->health <= 0)
{
Con_Printf("Refusing to save while dead.\n");
return;
}
}
//FIXME: we should probably block saving during intermission too.
/*catch invalid names*/ /*catch invalid names*/
if (!*savename || strstr(savename, "..")) if (!*savename || strstr(savename, ".."))
savename = "quicksav"; savename = "quicksav";