From 9c7ba654b58caa39f7172b66dcf764458acd3196 Mon Sep 17 00:00:00 2001 From: Spoike Date: Fri, 21 Jun 2019 03:59:46 +0000 Subject: [PATCH] Add a maptimes log, to display best times (and whether a map has actually been completed). update the qi plugin a little, and for maptimes. Try to fix a bug with android. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5480 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/client/m_download.c | 14 +- engine/client/sys_droid.c | 4 +- engine/common/common.h | 10 +- engine/common/fs.c | 38 ++++- engine/common/log.c | 156 ++++++++++++++++++ engine/common/plugin.c | 50 ++++-- engine/common/qvm.c | 10 +- engine/common/vm.h | 6 + .../src/com/fteqw/FTENativeActivity.java | 4 +- engine/gl/gl_shader.c | 54 +++--- engine/http/ftpserver.c | 2 +- engine/server/net_preparse.c | 7 + engine/server/pr_cmds.c | 4 + engine/server/sv_ccmds.c | 20 ++- engine/server/sv_user.c | 2 +- plugins/Makefile | 2 +- plugins/plugin.c | 6 + plugins/plugin.h | 2 + plugins/qi/qi.c | 34 ++-- 19 files changed, 349 insertions(+), 76 deletions(-) diff --git a/engine/client/m_download.c b/engine/client/m_download.c index ad74df559..161cc4ba2 100644 --- a/engine/client/m_download.c +++ b/engine/client/m_download.c @@ -1069,7 +1069,7 @@ void PM_EnumeratePlugins(void (*callback)(const char *name)) { if (d->dtype == DEP_FILE) { - if (!Q_strncasecmp(d->name, "fteplug_", 8)) + if (!Q_strncasecmp(d->name, PLUGINPREFIX, strlen(PLUGINPREFIX))) callback(d->name); } } @@ -1094,8 +1094,8 @@ static int QDECL PM_EnumeratedPlugin (const char *name, qofs_t size, time_t mtim char vmname[MAX_QPATH]; int len, l, a; char *dot; - if (!strncmp(name, "fteplug_", 8)) - Q_strncpyz(vmname, name+8, sizeof(vmname)); + if (!strncmp(name, PLUGINPREFIX, strlen(PLUGINPREFIX))) + Q_strncpyz(vmname, name+strlen(PLUGINPREFIX), sizeof(vmname)); else Q_strncpyz(vmname, name, sizeof(vmname)); len = strlen(vmname); @@ -1192,7 +1192,7 @@ static void PM_PreparePackageList(void) char nat[MAX_OSPATH]; FS_NativePath("", FS_BINARYPATH, nat, sizeof(nat)); Con_DPrintf("Loading plugins from \"%s\"\n", nat); - Sys_EnumerateFiles(nat, "fteplug_*" ARCH_DL_POSTFIX, PM_EnumeratedPlugin, &foundone, NULL); + Sys_EnumerateFiles(nat, PLUGINPREFIX"*" ARCH_DL_POSTFIX, PM_EnumeratedPlugin, &foundone, NULL); if (foundone && !pluginpromptshown) { pluginpromptshown = true; @@ -2076,7 +2076,7 @@ static void PM_PackageEnabled(package_t *p) if (!stricmp(ext, "pak") || !stricmp(ext, "pk3")) FS_ReloadPackFiles(); #ifdef PLUGINS - if ((p->flags & DPF_PLUGIN) && !Q_strncasecmp(dep->name, "fteplug_", 8)) + if ((p->flags & DPF_PLUGIN) && !Q_strncasecmp(dep->name, PLUGINPREFIX, strlen(PLUGINPREFIX))) Cmd_ExecuteString(va("plug_load %s\n", dep->name), RESTRICT_LOCAL); #endif #ifdef MENU_DAT @@ -2173,7 +2173,7 @@ static void PM_Download_Got(struct dl_download *dl) if (!stricmp(ext, "pak") || !stricmp(ext, "pk3")) FS_UnloadPackFiles(); //we reload them after #ifdef PLUGINS - if ((!stricmp(ext, "dll") || !stricmp(ext, "so")) && !Q_strncmp(dep->name, "fteplug_", 8)) + if ((!stricmp(ext, "dll") || !stricmp(ext, "so")) && !Q_strncmp(dep->name, PLUGINPREFIX, strlen(PLUGINPREFIX))) Cmd_ExecuteString(va("plug_close %s\n", dep->name), RESTRICT_LOCAL); //try to purge plugins so there's no files left open #endif @@ -2509,7 +2509,7 @@ void PM_ApplyChanges(void) reloadpacks = true; #ifdef PLUGINS //when disabling/purging plugins, be sure to unload them first (unfortunately there might be some latency before this can actually happen). - if ((p->flags & DPF_PLUGIN) && !Q_strncasecmp(dep->name, "fteplug_", 8)) + if ((p->flags & DPF_PLUGIN) && !Q_strncasecmp(dep->name, PLUGINPREFIX, strlen(PLUGINPREFIX))) Cmd_ExecuteString(va("plug_close %s\n", dep->name), RESTRICT_LOCAL); //try to purge plugins so there's no files left open #endif diff --git a/engine/client/sys_droid.c b/engine/client/sys_droid.c index cde26766b..2e1ebc636 100644 --- a/engine/client/sys_droid.c +++ b/engine/client/sys_droid.c @@ -1173,7 +1173,7 @@ static jboolean FTENativeActivity_startup(JNIEnv *jni, jobject this, jstring ext static void FTENativeActivity_surfacechange(JNIEnv *env, jobject this, jboolean teardown, jboolean recreate, jobject surface) { - if (this == sys_activity) + if (!(*env)->IsSameObject(env, this, sys_activity)) { LOGI("FTENativeActivity_surfacechange: inactive %p, active %p\n", this, sys_activity); return; //wasn't me... @@ -1200,7 +1200,7 @@ static void FTENativeActivity_surfacechange(JNIEnv *env, jobject this, jboolean } static void FTENativeActivity_shutdown(JNIEnv *env, jobject this) { - if (this != sys_activity) + if (!(*env)->IsSameObject(env, this, sys_activity)) { LOGI("FTENativeActivity_shutdown: inactive %p, active %p\n", this, sys_activity); return; //wasn't me... diff --git a/engine/common/common.h b/engine/common/common.h index 8c339fa13..e09eae3ae 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -526,9 +526,10 @@ struct vfsfile_s; //standard return value is 0 on failure, or depth on success. int FS_FLocateFile(const char *filename, unsigned int flags, flocation_t *loc); struct vfsfile_s *FS_OpenReadLocation(flocation_t *location); -char *FS_WhichPackForLocation(flocation_t *loc, qboolean makereferenced); +const char *FS_WhichPackForLocation(flocation_t *loc, qboolean makereferenced); qboolean FS_GetLocMTime(flocation_t *location, time_t *modtime); -char *FS_GetPackageDownloadFilename(flocation_t *loc); +const char *FS_GetPackageDownloadFilename(flocation_t *loc); //returns only packages (or null) +const char *FS_GetRootPackagePath(flocation_t *loc); //favours packages, but falls back on gamedirs. qboolean FS_GetPackageDownloadable(const char *package); char *FS_GetPackHashes(char *buffer, int buffersize, qboolean referencedonly); @@ -867,6 +868,11 @@ qboolean IPLog_Merge_File(const char *fname); #endif qboolean CertLog_ConnectOkay(const char *hostname, void *cert, size_t certsize); +#if defined(HAVE_SERVER) && defined(HAVE_CLIENT) +qboolean Log_CheckMapCompletion(const char *packagename, const char *mapname, float *besttime, float *fulltime, float *bestkills, float *bestsecrets); +void Log_MapNowCompleted(void); +#endif + /*used by and for botlib and q3 gamecode*/ #define MAX_TOKENLENGTH 1024 diff --git a/engine/common/fs.c b/engine/common/fs.c index 1bef56555..1cb3158f6 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -1387,10 +1387,38 @@ fail: return depth+1; } +//returns the location's root package (or gamedir). +//(aka: loc->search->purepath, but stripping contained nested packs) +const char *FS_GetRootPackagePath(flocation_t *loc) +{ + searchpath_t *sp, *search; + + for (sp = loc->search; ;) + { + for (search = com_searchpaths; search; search = search->next) + { + if (search != sp) + if (search->handle->GeneratePureCRC) //only consider files that have a pure hash. this excludes system paths + if (!strncmp(search->purepath, sp->purepath, strlen(search->purepath))) + if (sp->purepath[strlen(search->purepath)] == '/') //also ensures that the path gets shorter, avoiding infinite loops as it fights between base+home dirs. + break; + } + if (search) + sp = search; + else + break; + } + + // + if (sp) + return sp->purepath; + return NULL; +} + //returns the package/'gamedir/foo.pk3' filename to tell the client to download //unfortunately foo.pk3 may contain a 'bar.pk3' and downloading dir/foo.pk3/bar.pk3 won't work //so if loc->search is dir/foo.pk3/bar.pk3 find dir/foo.pk3 instead -char *FS_GetPackageDownloadFilename(flocation_t *loc) +const char *FS_GetPackageDownloadFilename(flocation_t *loc) { searchpath_t *sp, *search; @@ -1414,7 +1442,7 @@ char *FS_GetPackageDownloadFilename(flocation_t *loc) return sp->purepath; return NULL; } -char *FS_WhichPackForLocation(flocation_t *loc, qboolean makereferenced) +const char *FS_WhichPackForLocation(flocation_t *loc, qboolean makereferenced) { char *ret; if (!loc->search) @@ -6199,6 +6227,12 @@ static void FS_ChangeMod_f(void) arg = va("map \"%s\"\n", Cmd_Argv(i++)); fs_loadedcommand = Z_StrDup(arg); } + else if (!strcmp(arg, "spmap")) + { + Z_Free(fs_loadedcommand); + arg = va("deathmatch 0;coop 0;spmap \"%s\"\n", Cmd_Argv(i++)); + fs_loadedcommand = Z_StrDup(arg); + } else if (!strcmp(arg, "restart")) { Z_Free(fs_loadedcommand); diff --git a/engine/common/log.c b/engine/common/log.c index 19415690c..88d52051c 100644 --- a/engine/common/log.c +++ b/engine/common/log.c @@ -795,8 +795,164 @@ qboolean CertLog_ConnectOkay(const char *hostname, void *cert, size_t certsize) } #endif + + +#if defined(HAVE_SERVER) && defined(HAVE_CLIENT) +static struct maplog_entry +{ + struct maplog_entry *next; + float bestkills; + float bestsecrets; + float besttime; //updated when besttime=newkills + char name[1]; +} *maplog_enties; +static void Log_MapsRead(void) +{ + struct maplog_entry *m, **link = &maplog_enties; + vfsfile_t *f; + static qboolean maplog_loaded; + char line[8192], *s; + if (maplog_loaded) + return; + maplog_loaded = true; + f = FS_OpenVFS("maptimes.txt", "rb", FS_ROOT); + if (!f) + return; //no info yet. + while (VFS_GETS(f, line, sizeof(line))) + { + s = line; + s = COM_Parse(s); + m = Z_Malloc(sizeof(*m) + strlen(com_token)); + strcpy(m->name, com_token); + + s = COM_Parse(s); + m->besttime = atof(com_token); + s = COM_Parse(s); + m->fulltime = atof(com_token); + s = COM_Parse(s); + m->bestkills = atof(com_token); + s = COM_Parse(s); + m->bestsecrets = atof(com_token); + + *link = m; + link = &m->next; + } + VFS_CLOSE(f); +} +struct maplog_entry *Log_FindMap(const char *purepackage, const char *mapname) +{ + const char *name = va("%s/%s", purepackage, mapname); + struct maplog_entry *m; + Log_MapsRead(); + for (m = maplog_enties; m; m = m->next) + { + if (!strcmp(m->name, name)) + break; + } + return m; +} +static void Log_MapsDump(void) +{ + if (maplog_enties) + { + struct maplog_entry *m; + vfsfile_t *f = FS_OpenVFS("maptimes.txt", "wbp", FS_ROOT); + if (f) + { + for(m = maplog_enties; m; m = m->next) + { + VFS_PRINTF(f, "\"%s\" %.9g %.9g %.9g %.9g\n", m->name, m->besttime, m->fulltime, m->bestkills, m->bestsecrets); + } + VFS_CLOSE(f); + } + } +} +qboolean Log_CheckMapCompletion(const char *packagename, const char *mapname, float *besttime, float *fulltime, float *bestkills, float *bestsecrets) +{ + struct maplog_entry *m; + if (!packagename) + { + flocation_t loc; + if (!FS_FLocateFile(mapname, FSLF_DONTREFERENCE|FSLF_IGNORELINKS, &loc)) + return false; //no idea which package, don't guess. + packagename = FS_GetRootPackagePath(&loc); + if (!packagename) + return false; + } + m = Log_FindMap(packagename, mapname); + if (m) + { + *besttime = m->besttime; + *fulltime = m->fulltime; + *bestkills = m->bestkills; + *bestsecrets = m->bestsecrets; + return true; + } + return false; +} +void Log_MapNowCompleted(void) +{ + struct maplog_entry *m; + flocation_t loc; + float kills, secrets, oldprogress, newprogress, maptime; + const char *packagename; + + //don't log it if its deathmatch/coop/cheating. + extern int sv_allow_cheats; + if (deathmatch.ival || coop.ival || sv_allow_cheats == 1) + return; + + if (!FS_FLocateFile(sv.world.worldmodel->name, FSLF_DONTREFERENCE|FSLF_IGNORELINKS, &loc)) + { + Con_Printf("completion log: unable to determine logical path for map\n"); + return; //don't know + } + packagename = FS_GetRootPackagePath(&loc); + if (!packagename) + { + Con_Printf("completion log: unable to determine logical path for map\n"); + return; + } + + m = Log_FindMap(packagename, sv.world.worldmodel->name); + if (!m) + { + m = Z_Malloc(sizeof(*m)+strlen(packagename)+strlen(sv.world.worldmodel->name)+2); + sprintf(m->name, "%s/%s", packagename, sv.world.worldmodel->name); + + m->fulltime = m->besttime = INFINITY; + m->bestkills = m->bestsecrets = 0; + m->next = maplog_enties; + maplog_enties = m; + } + + kills = pr_global_struct->killed_monsters; + secrets = pr_global_struct->found_secrets; + maptime = sv.world.physicstime; + + newprogress = secrets*10+kills; + oldprogress = m->bestsecrets*10+m->bestkills; + + //if they got a new time record, update. + if (maptimebesttime) + m->besttime = maptime; + //if they got a new kills record, update + if (newprogress > oldprogress || (newprogress==oldprogress && maptimefulltime)) + { + m->bestkills = kills; + m->bestsecrets = secrets; + m->fulltime = maptime; + } +} +#endif + void Log_ShutDown(void) { +#if defined(HAVE_SERVER) && defined(HAVE_CLIENT) + Log_MapsDump(); +#endif + #ifdef IPLOG if (iplog_autodump.ival) IPLog_Dump("iplog.txt"); diff --git a/engine/common/plugin.c b/engine/common/plugin.c index 826cb2785..db677c3ba 100644 --- a/engine/common/plugin.c +++ b/engine/common/plugin.c @@ -252,8 +252,8 @@ static char *Plug_CleanName(const char *file, char *out, size_t sizeof_out) //"fteplug_ezhud_x86.REV.dll" gets converted into "ezhud" //skip fteplug_ - if (!Q_strncasecmp(file, "fteplug_", 8)) - file += 8; + if (!Q_strncasecmp(file, PLUGINPREFIX, strlen(PLUGINPREFIX))) + file += strlen(PLUGINPREFIX); //strip .REV.dll COM_StripAllExtensions(file, out, sizeof_out); @@ -283,19 +283,21 @@ static plugin_t *Plug_Load(const char *file, int type) newplug->name = (char*)(newplug+1); strcpy(newplug->name, temp); - if (!newplug->vm && (type & PLUG_NATIVE) && !Q_strncasecmp(file, "fteplug_", 8) && !Q_strcasecmp(ARCH_DL_POSTFIX+1, COM_FileExtension(file, temp, sizeof(temp)))) + if (!newplug->vm && (type & PLUG_NATIVE) && !Q_strncasecmp(file, PLUGINPREFIX, strlen(PLUGINPREFIX)) && !Q_strcasecmp(ARCH_DL_POSTFIX+1, COM_FileExtension(file, temp, sizeof(temp)))) { COM_StripExtension(file, temp, sizeof(temp)); newplug->vm = VM_Create(temp, Plug_SystemCallsNative, NULL, NULL); } +#ifndef ANDROID if (!newplug->vm && (type & PLUG_NATIVE)) { - Q_snprintfz(temp, sizeof(temp), "fteplug_%s_", file); + Q_snprintfz(temp, sizeof(temp), PLUGINPREFIX"%s_", file); newplug->vm = VM_Create(temp, Plug_SystemCallsNative, NULL, NULL); } +#endif if (!newplug->vm && (type & PLUG_NATIVE)) { - Q_snprintfz(temp, sizeof(temp), "fteplug_%s", file); + Q_snprintfz(temp, sizeof(temp), PLUGINPREFIX"%s", file); newplug->vm = VM_Create(temp, Plug_SystemCallsNative, NULL, NULL); } if (!newplug->vm && (type & PLUG_QVM)) @@ -355,7 +357,7 @@ static int QDECL Plug_EnumeratedRoot (const char *name, qofs_t size, time_t mtim char vmname[MAX_QPATH]; int len; char *dot; - if (!strncmp(name, "fteplug_", 8)) + if (!strncmp(name, PLUGINPREFIX, strlen(PLUGINPREFIX))) name += 8; Q_strncpyz(vmname, name, sizeof(vmname)); len = strlen(vmname); @@ -1530,6 +1532,28 @@ static qintptr_t VARGS Plug_UpdateInputBuffer(void *offset, quintptr_t mask, con return bufferlen; } +#if defined(HAVE_SERVER) && defined(HAVE_CLIENT) +qboolean FS_PathURLCache(const char *url, char *path, size_t pathsize); +static qintptr_t VARGS Plug_MapLog_Query(void *offset, quintptr_t mask, const qintptr_t *arg) +{ + const char *packagename = VM_POINTER(arg[0]); + const char *mapname = VM_POINTER(arg[1]); + float *vals = VM_POINTER(arg[2]); + if (VM_OOB(arg[2], sizeof(*vals)*4)) + return false; + if (!strncmp(packagename, "http://", 7) || !strncmp(packagename, "https://", 8)) + { + char temp[MAX_OSPATH]; + if (!FS_PathURLCache(packagename, temp, sizeof(temp))) + return false; + if (Log_CheckMapCompletion(temp, mapname, &vals[0], &vals[1], &vals[2], &vals[3])) + return true; + return false; + } + return Log_CheckMapCompletion(packagename, mapname, &vals[0], &vals[1], &vals[2], &vals[3]); +} +#endif + #ifdef USERBE #include "pr_common.h" //functions useful for rigid body engines. @@ -1567,7 +1591,7 @@ static void Plug_Load_f(void) Con_Printf("Loads a plugin\n"); Con_Printf("plug_load [pluginpath]\n"); Con_Printf("example pluginpath: blah\n"); - Con_Printf("will load fteplug_blah"ARCH_CPU_POSTFIX ARCH_DL_POSTFIX" or $gamedir/plugins/blah.qvm\n"); + Con_Printf("will load "PLUGINPREFIX"blah"ARCH_CPU_POSTFIX ARCH_DL_POSTFIX" or $gamedir/plugins/blah.qvm\n"); return; } if (!Plug_Load(plugin, PLUG_EITHER)) @@ -1695,6 +1719,10 @@ void Plug_Initialise(qboolean fromgamedir) #endif Plug_RegisterBuiltin("PR_GetVMInstance", Plug_PR_GetVMInstance, PLUG_BIF_DLLONLY); +#if defined(HAVE_SERVER) && defined(HAVE_CLIENT) + Plug_RegisterBuiltin("MapLog_Query", Plug_MapLog_Query, 0); +#endif + Plug_Client_Init(); } @@ -1707,7 +1735,7 @@ void Plug_Initialise(qboolean fromgamedir) { FS_NativePath("", FS_BINARYPATH, nat, sizeof(nat)); Con_DPrintf("Loading plugins from \"%s\"\n", nat); - Sys_EnumerateFiles(nat, "fteplug_*" ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, Plug_EnumeratedRoot, NULL, NULL); + Sys_EnumerateFiles(nat, PLUGINPREFIX"*" ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, Plug_EnumeratedRoot, NULL, NULL); } if (fromgamedir) { @@ -2201,7 +2229,7 @@ int QDECL Plug_List_Print(const char *fname, qofs_t fsize, time_t modtime, void if (!Q_strncasecmp(existing, parm, strlen(parm)) && !Q_strcasecmp(existing+strlen(parm), fname)) return true; } - Con_Printf("^[%s%s\\type\\plug_load %s\\^]: not loaded\n", (const char*)parm, fname, plugname+((!Q_strncasecmp(plugname,"fteplug_", 8))?8:0)); + Con_Printf("^[%s%s\\type\\plug_load %s\\^]: not loaded\n", (const char*)parm, fname, plugname+((!Q_strncasecmp(plugname,PLUGINPREFIX, strlen(PLUGINPREFIX)))?strlen(PLUGINPREFIX):0)); } } return true; @@ -2223,14 +2251,14 @@ void Plug_List_f(void) { while ((mssuck=strchr(binarypath, '\\'))) *mssuck = '/'; - Sys_EnumerateFiles(binarypath, "fteplug_*" ARCH_DL_POSTFIX, Plug_List_Print, binarypath, NULL); + Sys_EnumerateFiles(binarypath, PLUGINPREFIX"*" ARCH_DL_POSTFIX, Plug_List_Print, binarypath, NULL); } if (FS_NativePath("", FS_ROOT, rootpath, sizeof(rootpath))) { while ((mssuck=strchr(rootpath, '\\'))) *mssuck = '/'; if (strcmp(binarypath, rootpath)) - Sys_EnumerateFiles(rootpath, "fteplug_*" ARCH_DL_POSTFIX, Plug_List_Print, rootpath, NULL); + Sys_EnumerateFiles(rootpath, PLUGINPREFIX"*" ARCH_DL_POSTFIX, Plug_List_Print, rootpath, NULL); } for (u = 0; staticplugins[u].name; u++) diff --git a/engine/common/qvm.c b/engine/common/qvm.c index 0bb83abe6..b913a2c69 100644 --- a/engine/common/qvm.c +++ b/engine/common/qvm.c @@ -106,7 +106,10 @@ qboolean QVM_LoadDLL(vm_t *vm, const char *name, qboolean binroot, void **vmMain if (binroot) { Con_DPrintf("Attempting to load native library: %s\n", name); - +#ifdef ANDROID + if (!hVM && FS_NativePath(dllname_anycpu, FS_BINARYPATH, fname, sizeof(fname))) + hVM = Sys_LoadLibrary(fname, funcs); +#else if (!hVM && FS_NativePath(dllname_archpri, FS_BINARYPATH, fname, sizeof(fname))) hVM = Sys_LoadLibrary(fname, funcs); if (!hVM && FS_NativePath(dllname_anycpu, FS_BINARYPATH, fname, sizeof(fname))) @@ -116,27 +119,32 @@ qboolean QVM_LoadDLL(vm_t *vm, const char *name, qboolean binroot, void **vmMain hVM = Sys_LoadLibrary(fname, funcs); if (!hVM && FS_NativePath(dllname_anycpu, FS_ROOT, fname, sizeof(fname))) hVM = Sys_LoadLibrary(fname, funcs); +#endif // run through the search paths iterator = NULL; while (!hVM && COM_IteratePaths(&iterator, NULL, 0, gpath, sizeof(gpath))) { +#ifndef ANDROID if (!hVM && FS_NativePath(va("%s_%s_"ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, name, gpath), FS_BINARYPATH, fname, sizeof(fname))) { Con_DLPrintf(2, "Loading native: %s\n", fname); hVM = Sys_LoadLibrary(fname, funcs); } +#endif if (!hVM && FS_NativePath(va("%s_%s"ARCH_DL_POSTFIX, name, gpath), FS_BINARYPATH, fname, sizeof(fname))) { Con_DLPrintf(2, "Loading native: %s\n", fname); hVM = Sys_LoadLibrary(fname, funcs); } +#ifndef ANDROID if (!hVM && FS_NativePath(va("%s_%s_"ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, name, gpath), FS_ROOT, fname, sizeof(fname))) { Con_DLPrintf(2, "Loading native: %s\n", fname); hVM = Sys_LoadLibrary(fname, funcs); } +#endif if (!hVM && FS_NativePath(va("%s_%s"ARCH_DL_POSTFIX, name, gpath), FS_ROOT, fname, sizeof(fname))) { Con_DLPrintf(2, "Loading native: %s\n", fname); diff --git a/engine/common/vm.h b/engine/common/vm.h index 5784664e4..74264f293 100644 --- a/engine/common/vm.h +++ b/engine/common/vm.h @@ -49,6 +49,12 @@ void Plug_SBar(playerview_t *pv); qboolean Plug_ServerMessage(char *buffer, int messagelevel); void Plug_Tick(void); qboolean Plugin_ExecuteString(void); + +#ifdef ANDROID +#define PLUGINPREFIX "libplug_" //android is kinda annoying and only extracts specific files. +#else +#define PLUGINPREFIX "fteplug_" //this string defines what consitutes a plugin, as opposed to some other dll +#endif #endif diff --git a/engine/droid/src/com/fteqw/FTENativeActivity.java b/engine/droid/src/com/fteqw/FTENativeActivity.java index 31664f993..76b6466b5 100644 --- a/engine/droid/src/com/fteqw/FTENativeActivity.java +++ b/engine/droid/src/com/fteqw/FTENativeActivity.java @@ -104,8 +104,6 @@ public class FTENativeActivity extends android.app.Activity implements android.v // } super.onCreate(savedInstanceState); - //Needed because the InputQueue stuff blocks dispatchKeyEvent - getWindow().takeInputQueue(null); } //random helpers @@ -134,7 +132,7 @@ public class FTENativeActivity extends android.app.Activity implements android.v { try { - String secondary = (String) android.content.pm.ApplicationInfo.class.getField("nativeLibraryRootDir").get(context.getApplicationInfo()); + String secondary = (String) android.content.pm.ApplicationInfo.class.getField("nativeLibraryDir").get(context.getApplicationInfo()); return secondary; } catch (Exception e) diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index 85375b593..01f42f4a8 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -7866,42 +7866,34 @@ void R_RemapShader(const char *sourcename, const char *destname, float timeoffse { shader_t *o; shader_t *n; + int i; - //make sure all types of the shader are remapped properly. - //if there's a .shader file with it then it should 'just work'. + char cleansrcname[MAX_QPATH]; + Q_strncpyz(cleansrcname, sourcename, sizeof(cleansrcname)); + COM_CleanUpPath(cleansrcname); - o = R_LoadShader (sourcename, SUF_NONE, NULL, NULL); - n = R_LoadShader (destname, SUF_NONE, NULL, NULL); - if (o) + for (i = 0; i < r_numshaders; i++) { - if (!n) - n = o; - o->remapto = n; - o->remaptime = timeoffset; //this just feels wrong. - } - - o = R_LoadShader (sourcename, SUF_2D, NULL, NULL); - n = R_LoadShader (destname, SUF_2D, NULL, NULL); - if (o) - { - if (!n) - n = o; - o->remapto = n; - o->remaptime = timeoffset; - } - - o = R_LoadShader (sourcename, SUF_LIGHTMAP, NULL, NULL); - n = R_LoadShader (destname, SUF_LIGHTMAP, NULL, NULL); - if (o) - { - if (!n) + o = r_shaders[i]; + if (o && o->uses) { - n = R_LoadShader (destname, SUF_2D, NULL, NULL); - if (!n) - n = o; + if (!strcmp(o->name, cleansrcname)) + { + n = R_LoadShader (destname, o->usageflags, NULL, NULL); + if (!n) + { //if it isn't actually available on disk then don't care about usageflags, just find ANY that's already loaded. + // check the hash first + char cleandstname[MAX_QPATH]; + Q_strncpyz(cleandstname, destname, sizeof(cleandstname)); + COM_CleanUpPath(cleandstname); + n = Hash_Get(&shader_active_hash, cleandstname); + if (!n || !n->uses) + n = o; + } + o->remapto = n; + o->remaptime = timeoffset; //this just feels wrong. + } } - o->remapto = n; - o->remaptime = timeoffset; } } diff --git a/engine/http/ftpserver.c b/engine/http/ftpserver.c index 8d99226a8..9538c6f7b 100644 --- a/engine/http/ftpserver.c +++ b/engine/http/ftpserver.c @@ -66,7 +66,6 @@ SOCKET FTP_BeginListening(int aftype, int port) { struct sockaddr_qstorage address; unsigned long _true = true; - unsigned long _false = false; int i; SOCKET sock; @@ -116,6 +115,7 @@ SOCKET FTP_BeginListening(int aftype, int port) //2=ipv6 only if (aftype == 0) { + unsigned long _false = false; if (0 > setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&_false, sizeof(_false))) { //abort and do ipv4 only if hybrid sockets don't work. diff --git a/engine/server/net_preparse.c b/engine/server/net_preparse.c index f9f5ee157..3cb792153 100644 --- a/engine/server/net_preparse.c +++ b/engine/server/net_preparse.c @@ -728,6 +728,10 @@ void NPP_NQFlush(void) } #endif +#if defined(HAVE_CLIENT) + Log_MapNowCompleted(); +#endif + for (i = 0, cl = svs.clients; i < sv.allocated_client_slots; i++, cl++) { if (cl->state == cs_spawned && ISQWCLIENT(cl)) @@ -1758,6 +1762,9 @@ void NPP_QWFlush(void) break; //ignore these. case svc_intermission: +#if defined(HAVE_CLIENT) + Log_MapNowCompleted(); +#endif // if (writedest == &sv.reliable_datagram) { client_t *cl; diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index b6a57784f..5ae8e2d94 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -5925,6 +5925,10 @@ void QCBUILTIN PF_changelevel (pubprogfuncs_t *prinst, struct globalvars_s *pr_g return; sv.mapchangelocked = true; +#ifdef HAVE_CLIENT + Log_MapNowCompleted(); +#endif + #ifdef HEXEN2 if (progstype == PROG_H2) { diff --git a/engine/server/sv_ccmds.c b/engine/server/sv_ccmds.c index dfc8f2386..c9ccfc901 100644 --- a/engine/server/sv_ccmds.c +++ b/engine/server/sv_ccmds.c @@ -392,8 +392,24 @@ static int QDECL ShowMapList (const char *name, qofs_t flags, time_t mtime, void }; size_t u; char stripped[64]; + char completed[256]; if (name[5] == 'b' && name[6] == '_') //skip box models return true; + + *completed = 0; +#ifdef HAVE_CLIENT + { + float besttime, fulltime, kills, secrets; + if (Log_CheckMapCompletion(NULL, name, &besttime, &fulltime, &kills, &secrets)) + { + if (kills || secrets) + Q_snprintfz(completed, sizeof(completed), "^7 - ^2best: ^1%.1f^2, full: ^1%.1f^2 (^1%.0f^2 kills, ^1%.0f^2 secrets)", besttime, fulltime, kills, secrets); + else + Q_snprintfz(completed, sizeof(completed), "^7 - ^2best: ^1%.1f^2", besttime); + } + } +#endif + COM_StripExtension(name+5, stripped, sizeof(stripped)); for (u = 0; u < countof(levelshots); u++) { @@ -401,11 +417,11 @@ static int QDECL ShowMapList (const char *name, qofs_t flags, time_t mtime, void if (COM_FCheckExists(ls)) { Con_Printf("^[\\map\\%s\\img\\%s\\w\\64\\h\\48^]", stripped, ls); - Con_Printf("^[[%s]\\map\\%s\\tipimg\\%s^]\n", stripped, stripped, ls); + Con_Printf("^[[%s]%s\\map\\%s\\tipimg\\%s^]\n", stripped, completed, stripped, ls); return true; } } - Con_Printf("^[[%s]\\map\\%s^]\n", stripped, stripped); + Con_Printf("^[[%s]%s\\map\\%s^]\n", stripped, completed, stripped); return true; } static int QDECL ShowMapListExt (const char *name, qofs_t flags, time_t mtime, void *parm, searchpathfuncs_t *spath) diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index cbd1637d1..cb487faa2 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -3220,7 +3220,7 @@ static int SV_LocateDownload(const char *name, flocation_t *loc, char **replacem if (replacementname) { #if 1 - char *pakname = FS_GetPackageDownloadFilename(loc); + const char *pakname = FS_GetPackageDownloadFilename(loc); if (pakname && strchr(pakname, '/')) { extern cvar_t allow_download_packages,allow_download_copyrighted; //non authoritive, but should normally match. diff --git a/plugins/Makefile b/plugins/Makefile index af353ad76..5b5babb4d 100644 --- a/plugins/Makefile +++ b/plugins/Makefile @@ -68,7 +68,7 @@ ifeq ($(PLUG_NATIVE_EXT),) endif ifeq ($(FTE_TARGET),droid) #plugins get written to the tmp build dir, to avoid conflicts - PLUG_PREFIX=$(OUT_DIR)/m_droid-$(DROID_ARCH)/fteplug_ + PLUG_PREFIX=$(OUT_DIR)/m_droid-$(DROID_ARCH)/libplug_ #don't bother with cpu arch postfixes. they'll be in separate directories anyway. PLUG_NATIVE_EXT=.so #libresolv has no public api on android... diff --git a/plugins/plugin.c b/plugins/plugin.c index 085584cb7..94ccfe792 100644 --- a/plugins/plugin.c +++ b/plugins/plugin.c @@ -170,6 +170,10 @@ BUILTINR(int, GetLastInputFrame, (int seat, usercmd_t *playercmd)); BUILTINR(float, GetTrackerOwnFrags, (int seat, char *text, size_t textsize)); #undef ARGNAMES +#define ARGNAMES ,packagename,mapname,stats +BUILTINR(qboolean, MapLog_Query, (const char *packagename, const char *mapname, float *stats)); +#undef ARGNAMES + #ifndef Q3_VM #define ARGNAMES ,vmid BUILTINR(struct pubprogfuncs_s*, PR_GetVMInstance, (int vmid/*0=ss,1=cs,2=m*/)); @@ -526,6 +530,8 @@ static void Plug_InitStandardBuiltins(void) CHECKBUILTIN(Con_GetConsoleString); CHECKBUILTIN(Con_SetConsoleString); CHECKBUILTIN(Con_POpen); + + CHECKBUILTIN(MapLog_Query); } #ifndef Q3_VM diff --git a/plugins/plugin.h b/plugins/plugin.h index 79bcf7aff..46cf27fc4 100644 --- a/plugins/plugin.h +++ b/plugins/plugin.h @@ -261,6 +261,8 @@ EBUILTIN(int, GetLastInputFrame, (int seat, usercmd_t *playercmd)); #endif EBUILTIN(float, GetTrackerOwnFrags, (int seat, char *text, size_t textsize)); +EBUILTIN(qboolean, MapLog_Query, (const char *packagename, const char *mapname, float *stats)); + #ifndef Q3_VM struct pubprogfuncs_s; EBUILTIN(struct pubprogfuncs_s*, PR_GetVMInstance, (int vmid/*0=ss,1=cs,2=m*/)); diff --git a/plugins/qi/qi.c b/plugins/qi/qi.c index 5cb2f3b7a..5ac55e119 100644 --- a/plugins/qi/qi.c +++ b/plugins/qi/qi.c @@ -25,10 +25,10 @@ */ -xmltree_t *thedatabase; -qhandle_t dlcontext = -1; +static xmltree_t *thedatabase; +static qhandle_t dlcontext = -1; -struct +static struct { char namefilter[256]; int minrating; @@ -215,6 +215,7 @@ static void QI_RefreshMapList(qboolean forcedisplay) xmltree_t *file; const char *console = WINDOWNAME; char descbuf[1024]; + float donestats[4]; if (!QI_SetupWindow(console, forcedisplay)) return; @@ -257,16 +258,19 @@ static void QI_RefreshMapList(qboolean forcedisplay) switch(atoi(type)) { case 1: - type = "map"; + type = "map"; //'single map file(s)' break; case 2: - type = "mod"; + type = "mod"; //'Partial conversion' + break; + case 4: + type = "spd"; //'speedmapping' break; case 5: - type = "otr"; + type = "otr"; //'misc files' break; default: - type = "???"; + type = "???"; //no idea break; } @@ -320,20 +324,26 @@ static void QI_RefreshMapList(qboolean forcedisplay) year += 2000; else if (year < 1900) year += 1900; - Q_snprintf(descbuf, sizeof(descbuf), "Id: %s\nAuthor: %s\nDate: %04u-%02u-%02u\nRating: %s\n\n", id, author, year, month, day, ratingtext); + Q_snprintf(descbuf, sizeof(descbuf), "^aId:^a %s\n^aAuthor(s):^a %s\n^aDate:^a %04u-%02u-%02u\n^aRating:^a %s\n\n", id, author, year, month, day, ratingtext); QI_DeHTML(desc, descbuf + strlen(descbuf), sizeof(descbuf) - strlen(descbuf)); desc = descbuf; + Con_SubPrintf(console, "%s %s ^[^4%s: ^1%s\\tip\\%s\\tipimg\\"FILEIMAGEURL"\\id\\%s^]", type, ratingtext, id, XML_GetChildBody(file, "title", ""), desc, id, id); for (startmapnum = 0; ; startmapnum++) { + char bspfile[MAX_QPATH]; startmap = XML_ChildOfTree(tech, "startmap", startmapnum); if (!startmap) break; - Con_SubPrintf(console, "%s ^[%s (%s)\\tip\\%s\\tipimg\\"FILEIMAGEURL"\\id\\%s\\startmap\\%s^]\n", type, XML_GetChildBody(file, "title", ""), startmap->body, desc, id, id, startmap->body); + + Q_snprintf(bspfile, sizeof(bspfile), "maps/%s.bsp", startmap->body); + if (BUILTINISVALID(MapLog_Query) && pMapLog_Query(va(FILEDOWNLOADURL, id), bspfile, donestats)) + Con_SubPrintf(console, " ^[^2[%s, complete %.1f]\\tip\\^7^aBest Time:^a ^2%.9f^7\n^aCompletion Time:^a %.9f\n^aKills:^a %.9f\n^aSecrets:^a %.9f\n\n\n%s\\tipimg\\"FILEIMAGEURL"\\id\\%s\\startmap\\%s^]", startmap->body, donestats[0], donestats[0], donestats[1], donestats[2], donestats[3], desc, id, id, startmap->body); + else + Con_SubPrintf(console, " ^[^4[%s]\\tip\\%s\\tipimg\\"FILEIMAGEURL"\\id\\%s\\startmap\\%s^]", startmap->body, desc, id, id, startmap->body); } - if (!startmapnum) - Con_SubPrintf(console, "%s ^[%s\\tip\\%s\\tipimg\\"FILEIMAGEURL"\\id\\%s^]\n", type, XML_GetChildBody(file, "title", ""), desc, id, id); + Con_SubPrintf(console, "\n"); } Con_SubPrintf(console, "\nFilter:\n"); @@ -489,7 +499,7 @@ static void QI_RunMap(xmltree_t *qifile, const char *map) map = ""; - pCmd_AddText("fs_changemod map \"", false); + pCmd_AddText("fs_changemod spmap \"", false); pCmd_AddText(map, false); pCmd_AddText("\"", false); QI_AddPackages(qifile);