From 6d72f7487f4ce89e5f4e27043dbe2ab1d48beb8d Mon Sep 17 00:00:00 2001 From: Spoike Date: Mon, 9 Aug 2021 23:06:41 +0000 Subject: [PATCH] Tweak updates menu to allow launching package-specific maps (read: quaddicted's maps). git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@6017 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/client/m_download.c | 150 +++++++++++++++++++++++++++++++++++-- engine/client/menu.h | 1 + engine/common/log.c | 4 +- engine/server/sv_ccmds.c | 20 ++++- engine/server/sv_main.c | 3 +- 5 files changed, 165 insertions(+), 13 deletions(-) diff --git a/engine/client/m_download.c b/engine/client/m_download.c index e21ed6099..f43213af2 100644 --- a/engine/client/m_download.c +++ b/engine/client/m_download.c @@ -5094,6 +5094,7 @@ typedef struct { int downloadablessequence; char titletext[128]; char applymessage[128]; //so we can change its text to give it focus + const void *expandedpackage; //which package we're currently viewing maps for. qboolean populated; } dlmenu_t; @@ -5101,6 +5102,7 @@ static void MD_Draw (int x, int y, struct menucustom_s *c, struct emenu_s *m) { package_t *p; char *n; + struct packagedep_s *dep; if (y + 8 < 0 || y >= vid.height) //small optimisation. return; @@ -5113,6 +5115,23 @@ static void MD_Draw (int x, int y, struct menucustom_s *c, struct emenu_s *m) if (p->alternative && (p->flags & DPF_HIDDEN)) p = p->alternative; + for (dep = p->deps; dep; dep = dep->next) + if (dep->dtype == DEP_MAP) + break; + + if (dep) + { //map packages are not marked, but cached on demand. + if (p->flags & DPF_PRESENT) + { + if (p->flags & DPF_PURGE) + Draw_FunStringWidth (x, y, "DEL", 48, 2, false); //purge + else + Draw_FunStringWidth (x, y, "^&03 ", 48, 2, false); //cyan + } + else + Draw_FunStringWidth (x, y, "^&06 ", 48, 2, false); //orange + } + else #ifdef WEBCLIENT if (p->download) Draw_FunStringWidth (x, y, va("%i%%", (int)p->download->qdownload.percent), 48, 2, false); @@ -5199,7 +5218,7 @@ static void MD_Draw (int x, int y, struct menucustom_s *c, struct emenu_s *m) if ((p->flags & DPF_PURGE) || PM_PurgeOnDisable(p)) Draw_FunStringWidth (x, y, "DEL", 48, 2, false); else - Draw_FunStringWidth (x, y, "REM", 48, 2, false); + Draw_FunStringWidth (x, y, "DIS", 48, 2, false); } } } @@ -5233,16 +5252,42 @@ static qboolean MD_Key (struct menucustom_s *c, struct emenu_s *m, int key, unsi qboolean ctrl = keydown[K_LCTRL] || keydown[K_RCTRL]; package_t *p, *p2; struct packagedep_s *dep, *dep2; + dlmenu_t *info = m->data; if (c->dint != downloadablessequence) return false; //probably stale p = c->dptr; if (key == 'c' && ctrl) Sys_SaveClipboard(CBT_CLIPBOARD, p->website); - else if (key == K_ENTER || key == K_KP_ENTER || key == K_GP_START || key == K_MOUSE1) + else if (key == K_DEL || key == K_KP_DEL || key == K_BACKSPACE) + { + if (!(p->flags & DPF_MARKED)) + p->flags |= DPF_PURGE; //purge it when its already not marked (ie: when pressed twice) + PM_UnmarkPackage(p, DPF_MARKED); //deactivate it + } + else if (key == K_ENTER || key == K_KP_ENTER || key == K_GP_START || key == K_MOUSE1 || key == K_GP_A) { if (p->alternative && (p->flags & DPF_HIDDEN)) p = p->alternative; + if (info->expandedpackage == p) + { //close this submenu thing... + info->expandedpackage = NULL; + //remove the following map items. + downloadablessequence++; + return true; + } + + for (dep = p->deps; dep; dep = dep->next) + { + if (dep->dtype == DEP_MAP) + { + info->expandedpackage = p; + downloadablessequence++; + //add the map items after (and shift everything) + return true; + } + } + if (p->flags & DPF_ENABLED) { switch (p->flags & (DPF_PURGE|DPF_MARKED)) @@ -5341,6 +5386,66 @@ static qboolean MD_Key (struct menucustom_s *c, struct emenu_s *m, int key, unsi return false; } +static void MD_MapDraw (int x, int y, struct menucustom_s *c, struct emenu_s *m) +{ + const package_t *p = c->dptr; + struct packagedep_s *map = c->dptr2; + struct packagedep_s *dep; + float besttime, fulltime, bestkills, bestsecrets; + char *package = NULL; + const char *ext; + + if (y + 8 < 0 || y >= vid.height) //small optimisation. + return; + + if (c->dint != downloadablessequence) + return; //probably stale + + + for (dep = p->deps; dep; dep = dep->next) + { + if (dep->dtype == DEP_CACHEFILE) + { + package = va("downloads/%s", dep->name); + break; + } + else if (dep->dtype == DEP_FILE && !package) + package = dep->name; + } + ext = COM_GetFileExtension(map->name, NULL); + if (package && Log_CheckMapCompletion(package, va("maps/%s%s", map->name, *ext?"":".bsp"), &besttime, &fulltime, &bestkills, &bestsecrets)) + { + if (besttime != fulltime) + Draw_FunStringU8(CON_WHITEMASK, x+48+8*4, y, va("^m%s^m (%g %g in %.1f secs, fastest in %.1f)", map->name, bestkills,bestsecrets,fulltime, besttime)); + else + Draw_FunStringU8(CON_WHITEMASK, x+48+8*4, y, va("^m%s^m (%g %g in %.1f secs)", map->name, bestkills,bestsecrets,fulltime)); + } + else + Draw_FunStringU8(CON_WHITEMASK, x+48+8*4, y, map->name); +} +static qboolean MD_MapKey (struct menucustom_s *c, struct emenu_s *m, int key, unsigned int unicode) +{ + const package_t *p = c->dptr; + struct packagedep_s *map = c->dptr2; + struct packagedep_s *dep; + + if (c->dint != downloadablessequence) + return false; //probably stale + + if (key == K_ENTER || key == K_KP_ENTER || key == K_GP_START || key == K_MOUSE1 || key == K_GP_A) + for (dep = p->deps; dep; dep = dep->next) + { + if (dep == map) + { + char quoted[MAX_QPATH*2]; + Cbuf_AddText(va("map %s\n", COM_QuotedString(va("%s:%s", p->name, map->name), quoted, sizeof(quoted), false)), RESTRICT_LOCAL); + return true; + } + } + + return false; +} + #ifdef WEBCLIENT static void MD_Source_Draw (int x, int y, struct menucustom_s *c, struct emenu_s *m) { @@ -5512,7 +5617,25 @@ static qboolean MD_RevertUpdates (union menuoption_s *mo,struct emenu_s *m,int k return false; } -static int MD_AddItemsToDownloadMenu(emenu_t *m, int y, const char *pathprefix) +static int MD_AddMapItems(emenu_t *m, package_t *p, int y) +{ + struct packagedep_s *dep; + menucustom_t *c; + for (dep = p->deps; dep; dep = dep->next) + { + if (dep->dtype != DEP_MAP) + continue; + c = MC_AddCustom(m, 0, y, p, downloadablessequence, NULL); + c->dptr2 = dep; + c->draw = MD_MapDraw; + c->key = MD_MapKey; + c->common.width = 320-16; + c->common.height = 8; + y += 8; + } + return y; +} +static int MD_AddItemsToDownloadMenu(emenu_t *m, int y, const char *pathprefix, void *selpackage) { char path[MAX_QPATH]; package_t *p; @@ -5521,6 +5644,7 @@ static int MD_AddItemsToDownloadMenu(emenu_t *m, int y, const char *pathprefix) menuoption_t *mo; int prefixlen = strlen(pathprefix); struct packagedep_s *dep; + dlmenu_t *info = m->data; //add all packages in this dir for (p = availablepackages; p; p = p->next) @@ -5594,7 +5718,13 @@ static int MD_AddItemsToDownloadMenu(emenu_t *m, int y, const char *pathprefix) c->common.height = 8; y += 8; - if (!m->selecteditem) + if (info->expandedpackage == p) + { + m->selecteditem = (menuoption_t*)c; + + y = MD_AddMapItems(m, p, y); + } + if (!m->selecteditem || p == selpackage) m->selecteditem = (menuoption_t*)c; } } @@ -5627,7 +5757,7 @@ static int MD_AddItemsToDownloadMenu(emenu_t *m, int y, const char *pathprefix) MC_AddBufferedText(m, 48, 320-16, y, path+prefixlen, false, true); y += 8; Q_strncatz(path, "/", sizeof(path)); - y = MD_AddItemsToDownloadMenu(m, y, path); + y = MD_AddItemsToDownloadMenu(m, y, path, selpackage); } } } @@ -5649,6 +5779,8 @@ static void MD_Download_UpdateStatus(struct emenu_s *m) menucustom_t *c; qboolean sources; #endif + float framefrac = 0; + void *oldpackage = NULL; if (info->downloadablessequence != downloadablessequence || !info->populated) { @@ -5656,6 +5788,10 @@ static void MD_Download_UpdateStatus(struct emenu_s *m) { menuoption_t *op = m->options; m->options = op->common.next; + if (op->common.type == mt_frameend) + framefrac = op->frame.frac; + else if (m->selecteditem == op && op->common.type == mt_custom) + oldpackage = op->custom.dptr; if (op->common.iszone) Z_Free(op); } @@ -5784,11 +5920,11 @@ static void MD_Download_UpdateStatus(struct emenu_s *m) #endif y+=4; //small gap MC_AddBufferedText(m, 48, 320-16, y, "Packages", false, true), y += 8; - MD_AddItemsToDownloadMenu(m, y, info->pathprefix); + MD_AddItemsToDownloadMenu(m, y, info->pathprefix, oldpackage); if (!m->selecteditem) m->selecteditem = (menuoption_t*)d; m->cursoritem = (menuoption_t*)MC_AddWhiteText(m, 40, 0, m->selecteditem->common.posy, NULL, false); - MC_AddFrameEnd(m, 48); + MC_AddFrameEnd(m, 48)->frac = framefrac; } si = m->mouseitem; diff --git a/engine/client/menu.h b/engine/client/menu.h index f6f50de11..afaf3d7ba 100644 --- a/engine/client/menu.h +++ b/engine/client/menu.h @@ -240,6 +240,7 @@ typedef struct { typedef struct menucustom_s { menucommon_t common; void *dptr; + void *dptr2; int dint; void (*draw) (int x, int y, struct menucustom_s *, struct emenu_s *); qboolean (*key) (struct menucustom_s *, struct emenu_s *, int key, unsigned int unicode); diff --git a/engine/common/log.c b/engine/common/log.c index 4fb98dbf5..cffcd6dab 100644 --- a/engine/common/log.c +++ b/engine/common/log.c @@ -890,8 +890,10 @@ static void Log_MapsRead(void) } struct maplog_entry *Log_FindMap(const char *purepackage, const char *mapname) { - const char *name = va("%s/%s", purepackage, mapname); + char name[MAX_OSPATH]; struct maplog_entry *m; + if (Q_snprintfz(name, sizeof(name), "%s/%s", purepackage, mapname)) + return NULL; Log_MapsRead(); for (m = maplog_enties; m; m = m->next) { diff --git a/engine/server/sv_ccmds.c b/engine/server/sv_ccmds.c index c66a485e6..fffb8c609 100644 --- a/engine/server/sv_ccmds.c +++ b/engine/server/sv_ccmds.c @@ -493,6 +493,14 @@ static void SV_Map_c(int argn, const char *partial, struct xcommandargcompletion COM_EnumerateFiles(va("maps/%s*.cm", partial), CompleteMapList, ctx); COM_EnumerateFiles(va("maps/%s*.hmp", partial), CompleteMapList, ctx); + COM_EnumerateFiles(va("maps/%s*/*.bsp", partial), CompleteMapList, ctx); + COM_EnumerateFiles(va("maps/%s*/*.bsp.gz", partial), CompleteMapListExt, ctx); + COM_EnumerateFiles(va("maps/%s*/*.bsp.xz", partial), CompleteMapListExt, ctx); + COM_EnumerateFiles(va("maps/%s*/*.map", partial), CompleteMapListExt, ctx); + COM_EnumerateFiles(va("maps/%s*/*.map.gz", partial), CompleteMapListExt, ctx); + COM_EnumerateFiles(va("maps/%s*/*.cm", partial), CompleteMapList, ctx); + COM_EnumerateFiles(va("maps/%s*/*.hmp", partial), CompleteMapList, ctx); + #ifdef PACKAGEMANAGER PM_EnumerateMaps(partial, ctx); #endif @@ -552,7 +560,7 @@ void SV_Map_f (void) char level[MAX_QPATH]; char spot[MAX_QPATH]; char expanded[MAX_QPATH+64]; - char *nextserver; + char *nextserver = NULL; qboolean preserveplayers= false; qboolean isrestart = false; //don't hurt settings #ifdef SAVEDGAMES @@ -570,8 +578,6 @@ void SV_Map_f (void) int i; char *startspot; - nextserver = 0; - #ifndef SERVERONLY if (!Renderer_Started() && !isDedicated) { @@ -632,7 +638,13 @@ void SV_Map_f (void) if (sep) { *sep++ = 0; - PM_LoadMap(mangled, sep); + if (Cmd_FromGamecode()) + { + Con_TPrintf ("switching packages via %s command is blocked from gamecode, just in case.\n", Cmd_Argv(0)); + sv.mapchangelocked = false; + } + else + PM_LoadMap(mangled, sep); return; } } diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index 4bc373fa2..a26b0040d 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -618,7 +618,7 @@ void SV_DropClient (client_t *drop) } *drop->uploadfn = 0; -#ifndef SERVERONLY +#ifdef HAVE_CLIENT if (drop->netchan.remote_address.type == NA_LOOPBACK) { if (drop->protocol != SCP_BAD) @@ -627,6 +627,7 @@ void SV_DropClient (client_t *drop) #pragma warningmsg("This means that we may not see the reason we kicked ourselves.") #endif drop->state = cs_free; //don't do zombie stuff + cls.state = ca_disconnected; CL_BeginServerReconnect(); } else