misc tweaks to support:

opening (qtv) urls with android browser. mvds should stream using the same mechanism, if they have the right mime type.
arbitrary unicode basedirs in windows should work, and commandlines. not sure what else still doesn't work.


git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4539 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2013-11-28 00:45:22 +00:00
parent c5f51a6801
commit ad8d634916
16 changed files with 555 additions and 215 deletions

View File

@ -30,6 +30,16 @@ WHOAMI:=$(shell whoami)
#linux->nacl (FTE_TARGET=nacl NARCH=x86_64)
#if you are cross compiling, you'll need to use FTE_TARGET=mytarget
#cygwin's make's paths confuses non-cygwin things
RELEASE_DIR=$(BASE_DIR)/release
DEBUG_DIR=$(BASE_DIR)/debug
PROFILE_DIR=$(BASE_DIR)/profile
ifneq ($(shell uname -o 2>&1 | grep Cygwin),)
NATIVE_RELEASE_DIR=$(shell cygpath -m $(RELEASE_DIR))
NATIVE_DEBUG_DIR=$(shell cygpath -m $(DEBUG_DIR))
endif
#correct the gcc build when cross compiling
ifeq ($(FTE_TARGET),win32)
ifeq ($(shell $(CC) -v 2>&1 | grep mingw),)
@ -95,6 +105,8 @@ ifeq ($(FTE_TARGET),droid)
#set up for linux
TOOLCHAIN:=$(ANDROID_NDK_ROOT)/toolchains/arm-linux-androideabi-4.7/prebuilt/linux-x86/bin/arm-linux-androideabi-
else
#FIXME: support mingw too...
#we're running upon windows
ifeq ($(DROID_ARCH),x86)
TOOLCHAIN:=$(ANDROID_NDK_ROOT)/toolchains/x86-4.7/prebuilt/windows-x86_64/bin/i686-linux-android-
@ -275,9 +287,8 @@ PROGS_DIR=$(BASE_DIR)/qclib
NACL_DIR=$(BASE_DIR)/nacl
BOTLIB_DIR=$(BASE_DIR)/botlib
RELEASE_DIR=$(BASE_DIR)/release
DEBUG_DIR=$(BASE_DIR)/debug
PROFILE_DIR=$(BASE_DIR)/profile
#NATIVE_RELEASE_DIR?=$(RELEASE_DIR)
#NATIVE_DEBUG_DIR?=$(DEBUG_DIR)
ALL_CFLAGS=$(HAVECONFIG) $(VISIBILITY_FLAGS) $(CFLAGS) $(BASE_CFLAGS) $(WCFLAGS)
@ -1593,7 +1604,7 @@ endif
@echo
@$(JAVATOOL)jarsigner $(JARSIGNARGS) -digestalg SHA1 -sigalg MD5withRSA -keystore droid/ftekeystore droid/bin/FTEDroid-release-unsigned.apk autogen
-rm -f $(RELEASE_DIR)/FTEDroid.apk
$(ANDROID_HOME)/tools/zipalign 4 droid/bin/FTEDroid-release-unsigned.apk $(RELEASE_DIR)/FTEDroid.apk
$(ANDROID_HOME)/tools/zipalign 4 droid/bin/FTEDroid-release-unsigned.apk $(NATIVE_RELEASE_DIR)/FTEDroid.apk
droid-opt:
$(MAKE) FTE_TARGET=droid droid/build.xml droid/ftekeystore

View File

@ -74,6 +74,10 @@ void CL_StopPlayback (void)
cls.demoplayback = DPB_NONE;
cls.demoseeking = false; //just in case
if (cls.demoindownload)
cls.demoindownload->status = DL_FAILED;
cls.demoindownload = NULL;
if (cls.timedemo)
CL_FinishTimeDemo ();
}
@ -1550,15 +1554,53 @@ void CL_PlayDemo_f (void)
CL_PlayDemo(demoname);
}
void CL_PlayDemo(char *demoname)
void CL_DemoStreamFullyDownloaded(struct dl_download *dl)
{
char name[256];
int ft, neg = false;
int len;
char type;
char chr;
int protocol;
int start;
//let the file get closed by the demo playback code.
dl->file = NULL;
//kill the reference now that its done.
if (cls.demoindownload == dl)
cls.demoindownload = NULL;
}
//dl is provided so that we can receive files via chunked/gziped http downloads and on systems that don't provide sockets etc. its tracked so we can cancel the download if the client aborts playback early.
void CL_PlayDemoStream(vfsfile_t *file, struct dl_download *dl, char *filename, int demotype, float bufferdelay)
{
int protocol = CP_UNKNOWN;
if (demotype == DPB_NONE)
{
//peek etc?
}
switch(demotype)
{
case DPB_EZTV:
case DPB_MVD:
case DPB_QUAKEWORLD:
protocol = CP_QUAKEWORLD;
break;
#ifdef Q2CLIENT
case DPB_QUAKE2:
protocol = CP_QUAKE2;
break;
#endif
#ifdef NQPROT
case DPB_NETQUAKE:
protocol = CP_NETQUAKE;
break;
#endif
default:
break;
}
if (protocol == CP_UNKNOWN)
{
Con_Printf ("ERROR: demo format not supported: \"%s\".\n", filename);
return;
}
if (dl)
dl->notifycomplete = CL_DemoStreamFullyDownloaded;
//
// disconnect from server
@ -1568,32 +1610,78 @@ void CL_PlayDemo(char *demoname)
demo_flushcache();
//
// open the demo file
//
cls.demoindownload = dl;
cls.demoinfile = file;
if (!cls.demoinfile)
{
Con_Printf ("ERROR: couldn't open \"%s\".\n", filename);
cls.demonum = -1; // stop demo loop
return;
}
if (filename)
{
Q_strncpyz (lastdemoname, filename, sizeof(lastdemoname));
Con_Printf ("Playing demo from %s.\n", filename);
}
cls.findtrack = (demotype == DPB_MVD || demotype == DPB_EZTV);
cls.demoplayback = demotype;
cls.protocol = protocol;
cls.state = ca_demostart;
net_message.packing = SZ_RAWBYTES;
Netchan_Setup (NS_CLIENT, &cls.netchan, &net_from, 0);
demtime = -bufferdelay;
cl.gametime = -bufferdelay;
cl.gametimemark = demtime;
if (demtime < -0.5)
Con_Printf("Buffering for %g seconds\n", bufferdelay);
cls.netchan.last_received=demtime;
TP_ExecTrigger ("f_demostart");
}
void CL_PlayDemo(char *demoname)
{
char name[256];
int ft, neg = false;
int len;
char type;
char chr;
int protocol;
int start;
vfsfile_t *f;
//
// open the demo file
//
Q_strncpyz (name, demoname, sizeof(name));
COM_DefaultExtension (name, ".qwd", sizeof(name));
if (*name == '#')
cls.demoinfile = VFSOS_Open(name+1, "rb");
f = VFSOS_Open(name+1, "rb");
else
cls.demoinfile = FS_OpenVFS(name, "rb", FS_GAME);
if (!cls.demoinfile)
f = FS_OpenVFS(name, "rb", FS_GAME);
if (!f)
{
Q_strncpyz (name, demoname, sizeof(name));
COM_DefaultExtension (name, ".dem", sizeof(name));
if (*name == '#')
cls.demoinfile = VFSOS_Open(name+1, "rb");
f = VFSOS_Open(name+1, "rb");
else
cls.demoinfile = FS_OpenVFS(name, "rb", FS_GAME);
f = FS_OpenVFS(name, "rb", FS_GAME);
}
if (!cls.demoinfile)
if (!f)
{
Q_strncpyz (name, demoname, sizeof(name));
COM_DefaultExtension (name, ".mvd", sizeof(name));
if (*name == '#')
cls.demoinfile = VFSOS_Open(name+1, "rb");
f = VFSOS_Open(name+1, "rb");
else
cls.demoinfile = FS_OpenVFS(name, "rb", FS_GAME);
f = FS_OpenVFS(name, "rb", FS_GAME);
}
if (!cls.demoinfile)
if (!f)
{
Con_Printf ("ERROR: couldn't open \"%s\".\n", demoname);
cls.demonum = -1; // stop demo loop
@ -1602,115 +1690,56 @@ void CL_PlayDemo(char *demoname)
Q_strncpyz (lastdemoname, demoname, sizeof(lastdemoname));
Con_Printf ("Playing demo from %s.\n", name);
if (!VFS_GETLEN (cls.demoinfile))
if (!VFS_GETLEN (f))
{
VFS_CLOSE(cls.demoinfile);
cls.demoinfile = NULL;
VFS_CLOSE(f);
Con_Printf ("demo \"%s\" is empty.\n", demoname);
cls.demonum = -1; // stop demo loop
return;
}
if (!Q_strcasecmp(name + strlen(name) - 3, "mvd") ||
!Q_strcasecmp(name + strlen(name) - 6, "mvd.gz"))
{
cls.demoplayback = DPB_MVD;
cls.findtrack = true;
}
else
cls.demoplayback = DPB_QUAKEWORLD;
//figure out where we started
start = VFS_TELL(f);
cls.state = ca_demostart;
net_message.packing = SZ_RAWBYTES;
Netchan_Setup (NS_CLIENT, &cls.netchan, &net_from, 0);
demtime = 0;
cl.gametime = 0;
cl.gametimemark = demtime;
cls.netchan.last_received=demtime;
start = VFS_TELL(cls.demoinfile);
VFS_READ(cls.demoinfile, &len, sizeof(len));
VFS_READ(cls.demoinfile, &type, sizeof(type));
VFS_READ(cls.demoinfile, &protocol, sizeof(protocol));
VFS_SEEK(cls.demoinfile, start);
//check if its a quake2 demo.
VFS_READ(f, &len, sizeof(len));
VFS_READ(f, &type, sizeof(type));
VFS_READ(f, &protocol, sizeof(protocol));
VFS_SEEK(f, start);
if (len > 5 && type == svcq2_serverdata && protocol == PROTOCOL_VERSION_Q2)
{
#ifdef Q2CLIENT
cls.demoplayback = DPB_QUAKE2;
cls.protocol = CP_QUAKE2;
#else
Con_Printf ("ERROR: cannot play Quake2 demos.\n");
CL_StopPlayback();
CL_PlayDemoStream(f, NULL, name, DPB_QUAKE2, 0);
return;
#endif
}
else
//not quake2, check if its NQ
ft = 0; //work out if the first line is a int for the track number.
while ((VFS_READ(f, &chr, 1)==1) && (chr != '\n'))
{
ft = 0; //work out if the first line is a int for the track number.
while ((VFS_READ(cls.demoinfile, &chr, 1)==1) && (chr != '\n'))
{
if (chr == '-')
neg = true;
else if (chr < '0' || chr > '9')
break;
else
ft = ft * 10 + ((int)chr - '0');
}
if (neg)
ft *= -1;
if (chr == '\n')
{
#ifndef NQPROT
Con_Printf ("ERROR: cannot play NQ demos.\n");
CL_StopPlayback();
return;
#else
//fixme: play that cdtrack.
cls.protocol = CP_NETQUAKE;
cls.demoplayback = DPB_NETQUAKE; //nq demos. :o)
#endif
}
if (chr == '-')
neg = true;
else if (chr < '0' || chr > '9')
break;
else
{
cls.protocol = CP_QUAKEWORLD;
VFS_SEEK(cls.demoinfile, start); //quakeworld demo, so go back to start.
}
ft = ft * 10 + ((int)chr - '0');
}
if (neg)
ft *= -1;
if (chr == '\n')
{
CL_PlayDemoStream(f, NULL, name, DPB_NETQUAKE, 0);
return;
}
VFS_SEEK(f, start);
TP_ExecTrigger ("f_demostart");
}
//its not NQ then. must be QuakeWorld, either .qwd or .mvd
//could also be .qwz or .dmz or whatever that nq extension is. we don't support either.
void CL_QTVPlay (vfsfile_t *newf, qboolean iseztv)
{
CL_Disconnect_f ();
cls.demoinfile = newf;
demo_flushcache(); //just in case
if (iseztv)
cls.demoplayback = DPB_EZTV;
//mvd and qwd have no identifying markers, other than the extension.
if (!Q_strcasecmp(name + strlen(name) - 3, "mvd") ||
!Q_strcasecmp(name + strlen(name) - 6, "mvd.gz"))
CL_PlayDemoStream(f, NULL, name, DPB_MVD, 0);
else
cls.demoplayback = DPB_MVD;
cls.findtrack = true;
cls.state = ca_demostart;
net_message.packing = SZ_RAWBYTES;
Netchan_Setup (NS_CLIENT, &cls.netchan, &net_from, 0);
demtime = -BUFFERTIME;
cl.gametime = -BUFFERTIME;
cl.gametimemark = demtime;
if (demtime < -0.5)
Con_Printf("Buffering for %i seconds\n", (int)-demtime);
cls.netchan.last_received=realtime;
cls.protocol = CP_QUAKEWORLD;
TP_ExecTrigger ("f_demostart");
CL_PlayDemoStream(f, NULL, name, DPB_NETQUAKE, 0);
}
/*used with qtv*/
@ -1779,7 +1808,8 @@ void CL_QTVPoll (void)
if (qtvrequestsize >= sizeof(qtvrequestbuffer) - 1)
{
Con_Printf("%i of %i...\n", qtvrequestsize, (int)sizeof(qtvrequestbuffer));
//flag it as an error if the response is larger than we can handle.
//this error gets ignored if the header is okay (any actual errors will get reported again by the demo code anyway), and only counts if the end of the reply header was not found.
len = -1;
}
if (!qtvrequestsize && len == 0)
@ -1934,7 +1964,7 @@ void CL_QTVPoll (void)
if (streamavailable)
{
CL_QTVPlay(qtvrequest, iseztv);
CL_PlayDemoStream(qtvrequest, NULL, NULL, iseztv?DPB_EZTV:DPB_MVD, BUFFERTIME);
qtvrequest = NULL;
demo_resetcache(qtvrequestsize - (tail-qtvrequestbuffer), tail);
return;
@ -2219,7 +2249,7 @@ void CL_QTVPlay_f (void)
if (raw)
{
VFS_WRITE(newf, msg, msglen);
CL_QTVPlay(newf, false);
CL_PlayDemoStream(qtvrequest, NULL, qtvhostname, DPB_MVD, BUFFERTIME);
}
else
{

View File

@ -3586,13 +3586,20 @@ void Host_RunFileNotify(struct dl_download *dl)
#define HRF_NOOVERWRITE (1<<1)
#define HRF_ABORT (1<<3)
#define HRF_OPENED (1<<4)
#define HRF_DEMO (1<<8)
#define HRF_QTVINFO (1<<9)
#define HRF_MANIFEST (1<<10)
#define HRF_BSP (1<<11)
#define HRF_PACKAGE (1<<12)
#define HRF_DEMO_MVD (1<<8)
#define HRF_DEMO_QWD (1<<9)
#define HRF_DEMO_DM2 (1<<10)
#define HRF_DEMO_DEM (1<<11)
#define HRF_QTVINFO (1<<12)
#define HRF_MANIFEST (1<<13)
#define HRF_BSP (1<<14)
#define HRF_PACKAGE (1<<15)
#define HRF_ACTION (HRF_OVERWRITE|HRF_NOOVERWRITE|HRF_ABORT)
#define HRF_DEMO (HRF_DEMO_MVD|HRF_DEMO_QWD|HRF_DEMO_DM2|HRF_DEMO_DEM)
#define HRF_FILETYPES (HRF_DEMO|HRF_QTVINFO|HRF_MANIFEST|HRF_BSP|HRF_PACKAGE)
typedef struct {
unsigned int flags;
vfsfile_t *srcfile;
@ -3600,8 +3607,10 @@ typedef struct {
char fname[1]; //system path or url.
} hrf_t;
int waitingformanifest;
void Host_DoRunFile(hrf_t *f);
void CL_PlayDemoStream(vfsfile_t *file, struct dl_download *, char *filename, int demotype, float bufferdelay);
void CL_ParseQTVDescriptor(vfsfile_t *f, const char *name);
void Host_RunFileDownloaded(struct dl_download *dl)
{
@ -3612,6 +3621,75 @@ void Host_RunFileDownloaded(struct dl_download *dl)
Host_DoRunFile(f);
}
void Host_BeginFileDownload(struct dl_download *dl, char *mimetype)
{
//at this point the file is still downloading, so don't copy it out just yet.
hrf_t *f = dl->user_ctx;
if (mimetype && !(f->flags & HRF_FILETYPES))
{
if (!strcmp(mimetype, "application/x-qtv")) //what uses this?
f->flags |= HRF_QTVINFO;
else if (!strcmp(mimetype, "text/x-quaketvident"))
f->flags |= HRF_QTVINFO;
else if (!strcmp(mimetype, "application/x-ftemanifest"))
f->flags |= HRF_MANIFEST;
else if (!strcmp(mimetype, "application/x-multiviewdemo"))
f->flags |= HRF_MVD;
// else if (!strcmp(mimetype, "application/x-ftebsp"))
// f->flags |= HRF_BSP;
// else if (!strcmp(mimetype, "application/x-ftepackage"))
// f->flags |= HRF_PACKAGE;
}
//FIXME: HRF_DEMO should be able to stream. create a vfs pipe for the download code to write to?
if (!(f->flags & HRF_FILETYPES))
{
char *ext = COM_FileExtension(f->fname);
if (!strcmp(ext, "qwd"))
f->flags |= HRF_DEMO_QWD;
else if (!strcmp(ext, "mvd"))
f->flags |= HRF_DEMO_MVD;
else if (!strcmp(ext, "dm2"))
f->flags |= HRF_DEMO_DM2;
else if (!strcmp(ext, "dem"))
f->flags |= HRF_DEMO_DEM;
else if (!strcmp(ext, "qtv"))
f->flags |= HRF_QTVINFO;
else if (!strcmp(ext, "fmf"))
f->flags |= HRF_MANIFEST;
else if (!strcmp(ext, "bsp"))
f->flags |= HRF_BSP;
else if (!strcmp(ext, "pak") || !strcmp(ext, "pk3"))
f->flags |= HRF_PACKAGE;
else
{
//file type not guessable from extension.
f->flags |= HRF_ABORT;
Host_DoRunFile(f);
return;
}
if (f->flags & HRF_MANIFEST)
waitingformanifest++;
}
if (f->flags & HRF_DEMO_QWD)
CL_PlayDemoStream((dl->file = VFSPIPE_Open()), dl, f->fname, DPB_QUAKEWORLD, 0);
else if (f->flags & HRF_DEMO_MVD)
CL_PlayDemoStream((dl->file = VFSPIPE_Open()), dl, f->fname, DPB_MVD, 0);
else if (f->flags & HRF_DEMO_DM2)
CL_PlayDemoStream((dl->file = VFSPIPE_Open()), dl, f->fname, DPB_QUAKE2, 0);
else if (f->flags & HRF_DEMO_DEM)
CL_PlayDemoStream((dl->file = VFSPIPE_Open()), dl, f->fname, DPB_NETQUAKE, 0);
else
return;
f->flags |= HRF_ABORT;
Host_DoRunFile(f);
return;
}
void Host_RunFilePrompted(void *ctx, int button)
{
hrf_t *f = ctx;
@ -3630,7 +3708,6 @@ void Host_RunFilePrompted(void *ctx, int button)
Host_DoRunFile(f);
}
qboolean waitingformanifest;
void Host_DoRunFile(hrf_t *f)
{
char qname[MAX_QPATH];
@ -3652,6 +3729,50 @@ void Host_DoRunFile(hrf_t *f)
return;
}
if (!(f->flags & HRF_FILETYPES))
{
char *ext;
#ifdef WEBCLIENT
if (!strncmp(f->fname, "http://", 7) && !f->srcfile)
{
if (!(f->flags & HRF_OPENED))
{
struct dl_download *dl;
f->flags |= HRF_OPENED;
dl = HTTP_CL_Get(f->fname, NULL, Host_RunFileDownloaded);
dl->notifystarted = Host_BeginFileDownload;
dl->user_ctx = f;
return;
}
}
#endif
//if we get here, we have no mime type to give us any clues.
ext = COM_FileExtension(f->fname);
if (!strcmp(ext, "qwd") || !strcmp(ext, "dem") || !strcmp(ext, "dm2") || !strcmp(ext, "mvd"))
f->flags |= HRF_DEMO;
if (!strcmp(ext, "qtv"))
f->flags |= HRF_QTVINFO;
if (!strcmp(ext, "fmf"))
f->flags |= HRF_MANIFEST;
if (!strcmp(ext, "bsp"))
f->flags |= HRF_BSP;
if (!strcmp(ext, "pak") || !strcmp(ext, "pk3"))
f->flags |= HRF_PACKAGE;
//if we still don't know what it is, give up.
if (!(f->flags & HRF_FILETYPES))
{
f->flags |= HRF_ABORT;
Host_DoRunFile(f);
return;
}
if (f->flags & HRF_MANIFEST)
waitingformanifest++;
}
if (f->flags & HRF_DEMO)
{
//play directly via system path, no prompts needed
@ -3661,15 +3782,6 @@ void Host_DoRunFile(hrf_t *f)
Host_DoRunFile(f);
return;
}
else if (f->flags & HRF_QTVINFO)
{
//play directly via url/system path, no prompts needed
Cbuf_AddText(va("qtvplay \"#%s\"\n", f->fname), RESTRICT_LOCAL);
f->flags |= HRF_ABORT;
Host_DoRunFile(f);
return;
}
else if (f->flags & HRF_BSP)
{
char shortname[MAX_QPATH];
@ -3709,13 +3821,14 @@ void Host_DoRunFile(hrf_t *f)
}
}
}
else
else if (!(f->flags & HRF_QTVINFO))
{
f->flags |= HRF_ABORT;
Host_DoRunFile(f);
return;
}
//at this point we need the file to have been opened.
if (!(f->flags & HRF_OPENED))
{
f->flags |= HRF_OPENED;
@ -3725,6 +3838,7 @@ void Host_DoRunFile(hrf_t *f)
if (!strncmp(f->fname, "http://", 7))
{
struct dl_download *dl = HTTP_CL_Get(f->fname, NULL, Host_RunFileDownloaded);
dl->notifystarted = Host_BeginFileDownload;
dl->user_ctx = f;
return;
}
@ -3746,6 +3860,17 @@ void Host_DoRunFile(hrf_t *f)
return;
}
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);
f->srcfile = NULL;
f->flags |= HRF_ABORT;
Host_DoRunFile(f);
return;
}
VFS_SEEK(f->srcfile, 0);
f->dstfile = FS_OpenVFS(qname, "rb", FS_GAME);
@ -3818,25 +3943,10 @@ void Host_DoRunFile(hrf_t *f)
//if file is specified, takes full ownership of said file, including destruction.
qboolean Host_RunFile(const char *fname, int nlen, vfsfile_t *file)
{
char *ext = COM_FileExtension(fname);
hrf_t *f = Z_Malloc(sizeof(*f) + nlen);
memcpy(f->fname, fname, nlen);
f->fname[nlen] = 0;
if (!strcmp(ext, "qwd") || !strcmp(ext, "dem") || !strcmp(ext, "mvd"))
f->flags |= HRF_DEMO;
if (!strcmp(ext, "qtv"))
f->flags |= HRF_QTVINFO;
if (!strcmp(ext, "fmf"))
f->flags |= HRF_MANIFEST;
if (!strcmp(ext, "bsp"))
f->flags |= HRF_BSP;
if (!strcmp(ext, "pak") || !strcmp(ext, "pk3"))
f->flags |= HRF_PACKAGE;
if (f->flags & HRF_MANIFEST)
waitingformanifest++;
Host_DoRunFile(f);
return true;
}
@ -3894,7 +4004,6 @@ double Host_Frame (double time)
if (r_blockvidrestart)
{
extern qboolean waitingformanifest;
if (waitingformanifest)
return 0.1;
Host_FinishLoading();
@ -4284,10 +4393,10 @@ void CL_ExecInitialConfigs(char *resetcommand)
{
int qrc, hrc, def;
Cbuf_AddText("cl_warncmd 0\n", RESTRICT_LOCAL);
Cbuf_AddText("unbindall\n", RESTRICT_LOCAL);
Cbuf_AddText("cvar_purgedefaults\n", RESTRICT_LOCAL); //reset cvar defaults to their engine-specified values. the tail end of 'exec default.cfg' will update non-cheat defaults to mod-specified values.
Cbuf_AddText("cvarreset *\n", RESTRICT_LOCAL); //reset all cvars to their current (engine) defaults
Cbuf_AddText("cl_warncmd 0\n", RESTRICT_LOCAL);
Cbuf_AddText(resetcommand, RESTRICT_LOCAL);
Cbuf_AddText("\n", RESTRICT_LOCAL);

View File

@ -1413,7 +1413,7 @@ void CL_RequestNextDownload (void)
int stage;
/*already downloading*/
if (cls.downloadmethod)
if (cls.downloadmethod && !cls.demoplayback)
return;
/*request downloads only if we're at the point where we've received a complete list of them*/
@ -1442,7 +1442,7 @@ void CL_RequestNextDownload (void)
fl = dl->flags;
/*if we don't require downloads don't queue requests until we're actually on the server, slightly more deterministic*/
if (cls.state == ca_active || requiredownloads.value || (fl & DLLF_REQUIRED))
if (cls.state == ca_active || (requiredownloads.value && !cls.demoplayback) || (fl & DLLF_REQUIRED))
{
if ((fl & DLLF_OVERWRITE) || !CL_CheckFile (dl->localname))
{

View File

@ -415,6 +415,7 @@ typedef struct
float demoseektime;
qboolean timedemo;
vfsfile_t *demoinfile;
struct dl_download *demoindownload;
float td_lastframe; // to meter out one message a frame
int td_startframe; // host_framecount at start
float td_starttime; // realtime at second frame of timedemo

View File

@ -432,6 +432,7 @@ skipwhite:
return (char*)data;
}
#if 0
typedef struct
{
vfsfile_t funcs;
@ -513,7 +514,7 @@ vfsfile_t *VFSPIPE_Open(void)
return &newf->funcs;
}
#endif

View File

@ -1733,7 +1733,6 @@ WinMain
HINSTANCE global_hInstance;
int global_nCmdShow;
char *argv[MAX_NUM_ARGVS];
static char exename[MAX_PATH];
HWND hwnd_dialog;
@ -2548,6 +2547,58 @@ void VARGS Signal_Error_Handler(int i)
extern char sys_language[64];
static int Sys_ProcessCommandline(char **argv, int maxargc, char *argv0)
{
int argc = 0, i;
wchar_t *wc = GetCommandLineW();
unsigned char utf8cmdline[4096], *cl = utf8cmdline;
narrowen(utf8cmdline, sizeof(utf8cmdline), wc);
// argv[argc] = argv0;
// argc++;
while (*cl && (argc < maxargc))
{
while (*cl && *cl <= 32)
cl++;
if (*cl)
{
if (*cl == '\"')
{
cl++;
argv[argc] = cl;
argc++;
while (*cl && *cl != '\"')
cl++;
}
else
{
argv[argc] = cl;
argc++;
while (*cl && *cl > 32)
cl++;
}
if (*cl)
{
*cl = 0;
cl++;
}
}
}
argv[argc] = argv0;
if (argc < 1)
argc = 1;
for (i = 0; i < argc; i++)
argv[i] = strdup(argv[i]);
return i;
}
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
// MSG msg;
@ -2562,6 +2613,15 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
/* previous instances do not exist in Win32 */
if (hPrevInstance)
return 0;
/* determine if we're on nt early, so we don't do the wrong thing when checking commandlines */
{
OSVERSIONINFOA vinfo;
vinfo.dwOSVersionInfoSize = sizeof(vinfo);
if (GetVersionExA (&vinfo))
WinNT = vinfo.dwPlatformId == VER_PLATFORM_WIN32_NT;
}
#if defined(_DEBUG) && defined(MULTITHREAD)
Sys_SetThreadName(-1, "main thread");
#endif
@ -2626,44 +2686,6 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
global_hInstance = hInstance;
global_nCmdShow = nCmdShow;
parms.argc = 1;
argv[0] = exename;
while (*lpCmdLine && (parms.argc < MAX_NUM_ARGVS))
{
while (*lpCmdLine && ((*lpCmdLine <= 32) || (*lpCmdLine > 126)))
lpCmdLine++;
if (*lpCmdLine)
{
if (*lpCmdLine == '\"')
{
lpCmdLine++;
argv[parms.argc] = lpCmdLine;
parms.argc++;
while (*lpCmdLine && *lpCmdLine != '\"')
lpCmdLine++;
}
else
{
argv[parms.argc] = lpCmdLine;
parms.argc++;
while (*lpCmdLine && ((*lpCmdLine > 32) && (*lpCmdLine <= 126)))
lpCmdLine++;
}
if (*lpCmdLine)
{
*lpCmdLine = 0;
lpCmdLine++;
}
}
}
#ifdef RESTARTTEST
setjmp (restart_jmpbuf);
#endif
@ -2676,7 +2698,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
}
else
GetModuleFileNameA(NULL, bindir, sizeof(bindir)-1);
Q_strncpyz(exename, bindir, sizeof(exename));
parms.argc = Sys_ProcessCommandline(argv, MAX_NUM_ARGVS, bindir);
*COM_SkipPath(bindir) = 0;
parms.argv = (const char **)argv;
@ -2724,8 +2746,18 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
if (COM_CheckParm("-outputdebugstring"))
debugout = true;
if (!GetCurrentDirectory (sizeof(cwd), cwd))
Sys_Error ("Couldn't determine current directory");
if (WinNT)
{
wchar_t wcwd[MAX_OSPATH];
if (!GetCurrentDirectoryW (sizeof(wcwd)/sizeof(wchar_t), wcwd))
Sys_Error ("Couldn't determine current directory");
narrowen(cwd, sizeof(cwd), wcwd);
}
else
{
if (!GetCurrentDirectoryA (sizeof(cwd), cwd))
Sys_Error ("Couldn't determine current directory");
}
if (parms.argc >= 2)
{
if (*parms.argv[1] != '-' && *parms.argv[1] != '+')

View File

@ -2112,7 +2112,7 @@ int FTENET_GetLocalAddress(netadr_t *out, int port, int count, qboolean ipx, qbo
return idx;
}
#elif defined(__linux__)
#elif defined(__linux__) && !defined(ANDROID)
//in linux, looking up our own hostname to retrieve a list of local interface addresses will give no indication that other systems are able to do the same thing and is thus not supported.
//there's some special api instead
//glibc 2.3.
@ -5043,7 +5043,28 @@ void NET_GetLocalAddress (int socket, netadr_t *out)
if (out->type == NA_IP)
{
if (!*(int*)out->address.ip) //socket was set to auto
*(int *)out->address.ip = *(int *)adr.address.ip; //change it to what the machine says it is, rather than the socket.
{
if (adr.type == NA_IP)
*(int *)out->address.ip = *(int *)adr.address.ip; //change it to what the machine says it is, rather than the socket.
}
}
if (out->type == NA_IPV6)
{
if (!((int*)out->address.ip6)[0] &&
!((int*)out->address.ip6)[1] &&
!((short*)out->address.ip6)[4] &&
(!((short*)out->address.ip6)[5] || ((unsigned short*)out->address.ip6)[5]==0xffffu)
&& !((int*)out->address.ip6)[3]) //ipv6 any or ipv4-mapped any.
{
if (adr.type == NA_IP)
{
memset(out->address.ip6, 0, sizeof(out->address.ip6));
((short *)out->address.ip6)[5] = 0xffff;
((int *)out->address.ip6)[3] = *(int *)adr.address.ip;
}
else if (adr.type == NA_IPV6)
memcpy(out->address.ip6, adr.address.ip6, sizeof(out->address.ip6));
}
}
if (!notvalid)

View File

@ -522,7 +522,7 @@ static qboolean resetd3dbackbuffer(int width, int height)
static qboolean initD3D11Device(HWND hWnd, rendererstate_t *info, PFN_D3D11_CREATE_DEVICE_AND_SWAP_CHAIN func, IDXGIAdapter *adapt)
{
int flags = D3D11_CREATE_DEVICE_SINGLETHREADED;
int flags = 0;//= D3D11_CREATE_DEVICE_SINGLETHREADED;
D3D_DRIVER_TYPE drivertype;
DXGI_SWAP_CHAIN_DESC scd;
D3D_FEATURE_LEVEL flevel, flevels[] =

View File

@ -29660,6 +29660,14 @@
UsePrecompiledHeader="0"
/>
</FileConfiguration>
<FileConfiguration
Name="D3DRelease|Win32"
ExcludedFromBuild="true"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\common\net_ssl_winsspi.c"

View File

@ -13,16 +13,38 @@
<activity android:name=".FTEDroidActivity"
android:label="@string/app_name"
android:configChanges="keyboardHidden|orientation">
<!-- launcher icon -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!-- mime types with unspecified schemes (please don't explode). one for each mime type. because I'm paranoid. -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:mimeType="application/x-qtv" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:mimeType="text/x-quaketvident" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:mimeType="application/x-ftemanifest" />
</intent-filter>
<!-- various file extensions for when people forgot the mime type or simply don't know it -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" android:host="*" android:pathPattern=".*\\.qtv" />
<data android:scheme="content" android:host="*" android:pathPattern=".*\\.qtv" />
<data android:scheme="file" android:host="*" android:pathPattern=".*\\.qtv" />

View File

@ -725,12 +725,16 @@ public class FTEDroidActivity extends Activity
if (data.getScheme().equals("content"))
{ //wtf.
Cursor cursor = this.getContentResolver().query(data, null, null, null, null);
cursor.moveToFirst();
myloc = cursor.getString(0);
cursor.close();
cursor.moveToFirst();
myloc = cursor.getString(0);
cursor.close();
android.util.Log.i("FTEDroid", "intent content: " + myloc);
}
else
{
myloc = data.toString();
android.util.Log.i("FTEDroid", "intent url: " + myloc);
}
FTEDroidEngine.openfile(myloc);
}
}

View File

@ -325,6 +325,7 @@ static qboolean HTTP_DL_Work(struct dl_download *dl)
struct http_dl_ctx_s *con = dl->ctx;
char buffer[256];
char Location[256];
char mimetype[256];
char *nl;
char *msg;
int ammount;
@ -368,6 +369,10 @@ static qboolean HTTP_DL_Work(struct dl_download *dl)
msg = con->buffer;
con->chunking = false;
con->contentlength = 0;
con->gzip = false;
*mimetype = 0;
*Location = 0;
if (strnicmp(msg, "HTTP/", 5))
{ //pre version 1. (lame servers.
con->state = HC_GETTING;
@ -404,6 +409,12 @@ static qboolean HTTP_DL_Work(struct dl_download *dl)
break;//not complete, don't bother trying to parse it.
if (!strnicmp(msg, "Content-Length: ", 16))
con->contentlength = atoi(msg+16);
else if (!strnicmp(msg, "Content-Type:", 13))
{
*nl = '\0';
Q_strncpyz(mimetype, COM_TrimString(msg+13), sizeof(mimetype));
*nl = '\n';
}
else if (!strnicmp(msg, "Location: ", 10))
{
*nl = '\0';
@ -496,6 +507,9 @@ static qboolean HTTP_DL_Work(struct dl_download *dl)
memmove(con->buffer, con->buffer+ammount, con->bufferused);
}
if (dl->notifystarted)
dl->notifystarted(dl, *mimetype?mimetype:NULL);
if (!dl->file)
{
#ifndef NPFTE
@ -521,6 +535,8 @@ static qboolean HTTP_DL_Work(struct dl_download *dl)
con->file = FS_OpenTemp();
#else
Con_Printf("HTTP: no support for gzipped files \"%s\"\n", dl->localname);
dl->status = DL_FAILED;
return false;
#endif
}
else
@ -803,8 +819,8 @@ static int DL_Thread_Work(void *arg)
{
#ifdef NPFTE
//the plugin doesn't have a download loop
if (dl->notify)
dl->notify(dl);
if (dl->notifycomplete)
dl->notifycomplete(dl);
if (dl->file)
VFS_CLOSE(dl->file);
#else
@ -830,7 +846,7 @@ qboolean DL_CreateThread(struct dl_download *dl, vfsfile_t *file, void (*NotifyF
if (file)
dl->file = file;
if (NotifyFunction)
dl->notify = NotifyFunction;
dl->notifycomplete = NotifyFunction;
dl->threadctx = Sys_CreateThread("download", DL_Thread_Work, dl, THREADP_NORMAL, 0);
if (!dl->threadctx)
@ -896,14 +912,14 @@ void DL_Close(struct dl_download *dl)
static struct dl_download *activedownloads;
unsigned int shownbytestart;
/*create a download context and add it to the list, for lazy people*/
/*create a download context and add it to the list, for lazy people. not threaded*/
struct dl_download *HTTP_CL_Get(const char *url, const char *localfile, void (*NotifyFunction)(struct dl_download *dl))
{
struct dl_download *newdl = DL_Create(url);
if (!newdl)
return newdl;
newdl->notify = NotifyFunction;
newdl->notifycomplete = NotifyFunction;
if (localfile)
Q_strncpyz(newdl->localname, localfile, sizeof(newdl->localname));
@ -951,10 +967,10 @@ void HTTP_CL_Think(void)
if (!dl->poll(dl))
{
*link = dl->next;
if (dl->file)
if (dl->file && dl->file->Seek)
VFS_SEEK(dl->file, 0);
if (dl->notify)
dl->notify(dl);
if (dl->notifycomplete)
dl->notifycomplete(dl);
DL_Close(dl);
continue;
}
@ -992,3 +1008,86 @@ void HTTP_CL_Think(void)
}
#endif
#endif /*WEBCLIENT*/
typedef struct
{
vfsfile_t funcs;
char *data;
int maxlen;
int writepos;
int readpos;
} vfspipe_t;
void QDECL VFSPIPE_Close(vfsfile_t *f)
{
vfspipe_t *p = (vfspipe_t*)f;
free(p->data);
free(p);
}
unsigned long QDECL VFSPIPE_GetLen(vfsfile_t *f)
{
vfspipe_t *p = (vfspipe_t*)f;
return p->writepos - p->readpos;
}
//unsigned long QDECL VFSPIPE_Tell(vfsfile_t *f)
//{
// return 0;
//}
//qboolean QDECL VFSPIPE_Seek(vfsfile_t *f, unsigned long offset)
//{
// Con_Printf("Seeking is a bad plan, mmkay?\n");
// return false;
//}
int QDECL VFSPIPE_ReadBytes(vfsfile_t *f, void *buffer, int len)
{
vfspipe_t *p = (vfspipe_t*)f;
if (len > p->writepos - p->readpos)
len = p->writepos - p->readpos;
memcpy(buffer, p->data+p->readpos, len);
p->readpos += len;
if (p->readpos > 8192)
{
//shift the memory down periodically
//fixme: use cyclic buffer? max size, etc?
memmove(p->data, p->data+p->readpos, p->writepos-p->readpos);
p->writepos -= p->readpos;
p->readpos = 0;
}
return len;
}
int QDECL VFSPIPE_WriteBytes(vfsfile_t *f, const void *buffer, int len)
{
vfspipe_t *p = (vfspipe_t*)f;
if (p->writepos + len > p->maxlen)
{
p->maxlen = p->writepos + len;
p->data = realloc(p->data, p->maxlen);
}
memcpy(p->data+p->writepos, buffer, len);
p->writepos += len;
return len;
}
vfsfile_t *VFSPIPE_Open(void)
{
vfspipe_t *newf;
newf = malloc(sizeof(*newf));
newf->data = NULL;
newf->maxlen = 0;
newf->readpos = 0;
newf->writepos = 0;
newf->funcs.Close = VFSPIPE_Close;
newf->funcs.Flush = NULL;
newf->funcs.GetLen = VFSPIPE_GetLen;
newf->funcs.ReadBytes = VFSPIPE_ReadBytes;
newf->funcs.Seek = NULL;//VFSPIPE_Seek;
newf->funcs.Tell = NULL;//VFSPIPE_Tell;
newf->funcs.WriteBytes = VFSPIPE_WriteBytes;
newf->funcs.seekingisabadplan = true;
return &newf->funcs;
}

View File

@ -142,9 +142,11 @@ struct dl_download
/*not used internally by the backend, but used by HTTP_CL_Get/thread wrapper*/
struct dl_download *next;
void (*notify) (struct dl_download *dl);
void (*notifystarted) (struct dl_download *dl, char *mimetype); //mime can be null for some protocols, read dl->totalsize for size.
void (*notifycomplete) (struct dl_download *dl);
};
vfsfile_t *VFSPIPE_Open(void);
void HTTP_CL_Think(void);
struct dl_download *HTTP_CL_Get(const char *url, const char *localfile, void (*NotifyFunction)(struct dl_download *dl));
struct dl_download *HTTP_CL_Put(const char *url, const char *mime, const char *data, size_t datalen, void (*NotifyFunction)(struct dl_download *dl));

View File

@ -154,7 +154,7 @@ cvar_t sv_gamespeed = CVAR("sv_gamespeed", "1");
cvar_t sv_csqcdebug = CVAR("sv_csqcdebug", "0");
cvar_t sv_csqc_progname = CVAR("sv_csqc_progname", "csprogs.dat");
cvar_t pausable = CVAR("pausable", "1");
cvar_t sv_banproxies = CVARD("banproxies", "0", "If enabled, anyone connecting via known proxy software will be refused entry. This should aid with blocking aimbots, but is only reliable for certain public proxies.");
cvar_t sv_banproxies = CVARD("sv_banproxies", "0", "If enabled, anyone connecting via known proxy software will be refused entry. This should aid with blocking aimbots, but is only reliable for certain public proxies.");
//

View File

@ -79,7 +79,7 @@ cvar_t voteminimum = SCVAR("voteminimum", "4");
cvar_t votepercent = SCVAR("votepercent", "-1");
cvar_t votetime = SCVAR("votetime", "10");
cvar_t pr_allowbutton1 = SCVARF("pr_allowbutton1", "1", CVAR_LATCH);
cvar_t pr_allowbutton1 = CVARFD("pr_allowbutton1", "1", CVAR_LATCH, "The button1 field is believed to have been intended to work with the +use command, but it was never hooked up. In NetQuake, this field was often repurposed for other things as it was not otherwise used (and cannot be removed without breaking the crc), while third-party QuakeWorld engines did decide to implement it as believed was intended. As a result, this cvar only applies to QuakeWorld mods and a value of 1 is only likely to cause issues with NQ mods that were ported to QW.");
extern cvar_t sv_minping;
@ -5692,7 +5692,7 @@ void SV_RunCmd (usercmd_t *ucmd, qboolean recurse)
sv_player->v->button0 = ucmd->buttons & 1;
sv_player->v->button2 = (ucmd->buttons >> 1) & 1;
if (pr_allowbutton1.ival) //many mods use button1 - it's just a wasted field to many mods. So only work it if the cvar allows.
if (pr_allowbutton1.ival && progstype == PROG_QW) //many mods use button1 - it's just a wasted field to many mods. So only work it if the cvar allows.
sv_player->v->button1 = ((ucmd->buttons >> 2) & 1);
// DP_INPUTBUTTONS
sv_player->xv->button3 = ((ucmd->buttons >> 2) & 1);
@ -6813,7 +6813,7 @@ void SVNQ_ReadClientMove (usercmd_t *move)
host_client->edict->v->button0 = bits & 1;
host_client->edict->v->button2 = (bits >> 1) & 1;
if (pr_allowbutton1.ival) //many mods use button1 - it's just a wasted field to many mods. So only work it if the cvar allows.
if (pr_allowbutton1.ival && progstype == PROG_QW) //many mods use button1 - it's just a wasted field to many mods. So only work it if the cvar allows.
host_client->edict->v->button1 = ((bits >> 2) & 1);
// DP_INPUTBUTTONS
host_client->edict->xv->button3 = ((bits >> 2) & 1);