Add basic support for ktx's 'mapname#modifier' ent stuff.

This commit is contained in:
Shpoike 2023-02-20 05:50:50 +00:00
parent 774fb93721
commit 1fe478dfa1
6 changed files with 113 additions and 8 deletions

View file

@ -184,6 +184,8 @@ void Mod_ParseEntities(struct model_s *mod);
void Mod_LoadMapArchive(struct model_s *mod, void *archivedata, size_t archivesize);
extern void Mod_ClearAll (void);
extern void Mod_Purge (enum mod_purge_e type);
extern void Mod_SetModifier (const char *modifier);
extern char mod_modifier[];
extern qboolean Mod_PurgeModel (struct model_s *mod, enum mod_purge_e ptype);
extern struct model_s *Mod_FindName (const char *name); //find without loading. needload should be set.
extern struct model_s *Mod_ForName (const char *name, enum mlverbosity_e verbosity); //finds+loads

View file

@ -7930,6 +7930,7 @@ void Mod_Terrain_Save_f(void)
{
//warning: brushes are not saved unless its a .map
COM_StripExtension(mod->name, fname, sizeof(fname));
Q_strncatz(fname, mod_modifier, sizeof(fname));
Q_strncatz(fname, ".ent", sizeof(fname));
FS_CreatePath(fname, FS_GAMEONLY);

View file

@ -81,6 +81,7 @@ void Mod_LoadDoomSprite (model_t *mod);
#define MAX_MOD_KNOWN 8192
model_t *mod_known;
int mod_numknown;
char mod_modifier[MAX_QPATH]; //postfix for ent files
extern cvar_t r_loadlits;
#ifdef SPECULAR
@ -620,6 +621,17 @@ void Mod_Purge(enum mod_purge_e ptype)
}
}
void Mod_SetModifier(const char *modifier)
{
if (!modifier || strlen(modifier) >= sizeof(mod_modifier)) modifier = "";
if (strcmp(modifier, mod_modifier))
{ //if the modifier changed, force all models to reset.
COM_WorkerFullSync(); //sync all the workers, just in case.
strcpy(mod_modifier, modifier);
Mod_Purge(MP_RESET); //nuke it now
}
}
#ifndef SERVERONLY
void Mod_FindCubemaps_f(void);
void Mod_Realign_f(void);
@ -2252,11 +2264,13 @@ static void Mod_SaveEntFile_f(void)
{
Q_snprintfz(fname, sizeof(fname), "maps/%s/%s", mod_loadentfiles_dir.string, mod->name+5);
COM_StripExtension(fname, fname, sizeof(fname));
Q_strncatz(fname, mod_modifier, sizeof(fname));
Q_strncatz(fname, ".ent", sizeof(fname));
}
else
{
COM_StripExtension(mod->name, fname, sizeof(fname));
Q_strncatz(fname, mod_modifier, sizeof(fname));
Q_strncatz(fname, ".ent", sizeof(fname));
}
@ -2293,6 +2307,7 @@ qboolean Mod_LoadEntitiesBlob(struct model_s *mod, const char *entdata, size_t e
{
Q_snprintfz(fname, sizeof(fname), "maps/%s/%s", mod_loadentfiles_dir.string, mod->name+5);
COM_StripExtension(fname, fname, sizeof(fname));
Q_strncatz(fname, mod_modifier, sizeof(fname));
Q_strncatz(fname, ".ent", sizeof(fname));
ents = FS_LoadMallocFile(fname, &sz);
}
@ -2300,12 +2315,14 @@ qboolean Mod_LoadEntitiesBlob(struct model_s *mod, const char *entdata, size_t e
if (mod_loadentfiles.value && !ents)
{
COM_StripExtension(mod->name, fname, sizeof(fname));
Q_strncatz(fname, mod_modifier, sizeof(fname));
Q_strncatz(fname, ".ent", sizeof(fname));
ents = FS_LoadMallocFile(fname, &sz);
}
if (mod_loadentfiles.value && !ents)
{ //tenebrae compat
COM_StripExtension(mod->name, fname, sizeof(fname));
Q_strncatz(fname, mod_modifier, sizeof(fname));
Q_strncatz(fname, ".edo", sizeof(fname));
ents = FS_LoadMallocFile(fname, &sz);
}

View file

@ -1090,11 +1090,21 @@ static qintptr_t QVM_SetSpawnParams (void *offset, quintptr_t mask, const qintpt
static qintptr_t QVM_ChangeLevel (void *offset, quintptr_t mask, const qintptr_t *arg)
{
const char *arg_mapname = VM_POINTER(arg[0]);
// const char *arg_entfilename = VM_POINTER(arg[1]);
const char *arg_entfilename = (qvm_api_version > 13)?(VM_POINTER(arg[1])):"";
char newmap[MAX_QPATH];
if (sv.mapchangelocked)
return 0;
if (arg_entfilename && *arg_entfilename)
{
int nl = strlen(arg_mapname);
if (!strncmp(arg_mapname, arg_entfilename, nl) && arg_mapname[nl]=='#')
arg_mapname = arg_entfilename;
else
Con_Printf(CON_ERROR"%s: named ent file does not match map\n", "QVM_ChangeLevel");
}
sv.mapchangelocked = true;
COM_QuotedString(arg_mapname, newmap, sizeof(newmap), false);
Cbuf_AddText (va("\nchangelevel %s\n", newmap), RESTRICT_LOCAL);
@ -1103,13 +1113,23 @@ static qintptr_t QVM_ChangeLevel (void *offset, quintptr_t mask, const qintptr_t
static qintptr_t QVM_ChangeLevelHub (void *offset, quintptr_t mask, const qintptr_t *arg)
{
const char *arg_mapname = VM_POINTER(arg[0]);
// const char *arg_entfile = VM_POINTER(arg[1]);
const char *arg_entfilename = VM_POINTER(arg[1]);
const char *arg_startspot = VM_POINTER(arg[2]);
char newmap[MAX_QPATH];
char startspot[MAX_QPATH];
if (sv.mapchangelocked)
return 0;
if (arg_entfilename && *arg_entfilename)
{
int nl = strlen(arg_mapname);
if (!strncmp(arg_mapname, arg_entfilename, nl) && arg_mapname[nl]=='#')
arg_mapname = arg_entfilename;
else
Con_Printf(CON_ERROR"%s: named ent file does not match map\n", "QVM_ChangeLevelHub");
}
sv.mapchangelocked = true;
COM_QuotedString(arg_mapname, newmap, sizeof(newmap), false);
COM_QuotedString(arg_startspot, startspot, sizeof(startspot), false);

View file

@ -471,6 +471,27 @@ static int QDECL CompleteMapList (const char *name, qofs_t flags, time_t mtime,
ctx->cb(stripped, NULL, NULL, ctx);
return true;
}
static int QDECL CompleteMapListEnt (const char *name, qofs_t flags, time_t mtime, void *parm, searchpathfuncs_t *spath)
{
struct xcommandargcompletioncb_s *ctx = parm;
char stripped[64];
char *modifier = strchr(name, '#');
if (!modifier) //skip non-modifiers.
return true;
if (modifier-name+4 > sizeof(stripped)) //too long...
return true;
//make sure we have its .bsp
memcpy(stripped, name, modifier-name);
strcpy(stripped+(modifier-name), ".bsp");
if (!COM_FCheckExists(stripped))
return true;
COM_StripExtension(name+5, stripped, sizeof(stripped));
ctx->cb(stripped, NULL, NULL, ctx);
return true;
}
static int QDECL CompleteMapListExt (const char *name, qofs_t flags, time_t mtime, void *parm, searchpathfuncs_t *spath)
{
struct xcommandargcompletioncb_s *ctx = parm;
@ -493,6 +514,8 @@ 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*.ent", partial), CompleteMapListEnt, 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);
@ -609,7 +632,7 @@ fte:
'map package:mapname' should download the specified map package and load up its maps.
mvdsv:
basemap#modifier.ent files
'map foo bar' should load 'maps/bar.ent' instead of the regular ent file. this 'bar' will usually be something like 'foo#modified'
======================
*/
@ -851,10 +874,25 @@ void SV_Map_f (void)
break;
}
if (!exts[i])
{ //try again.
char *mod = strchr(level, '#');
if (mod)
{
*mod = 0;
for (i = 0; exts[i]; i++)
{
snprintf (expanded, sizeof(expanded), exts[i], level);
if (COM_FCheckExists (expanded))
break;
}
*mod = '#';
}
}
if (!exts[i])
{
for (i = 0; exts[i]; i++)
{
//doesn't exist, so try lowercase. Q3 does this.
//doesn't exist, so try lowercase. Q3 does this. really our fs_cache stuff should be handling this, but its possible its disabled.
for (j = 0; j < sizeof(level) && level[j]; j++)
{
if (level[j] >= 'A' && level[j] <= 'Z')

View file

@ -1016,12 +1016,11 @@ void SV_SpawnServer (const char *server, const char *startspot, qboolean noents,
{
//.map is commented out because quite frankly, they're a bit annoying when the engine loads the gpled start.map when really you wanted to just play the damn game intead of take it apart.
//if you want to load a .map, just use 'map foo.map' instead.
char *exts[] = {"maps/%s", "maps/%s.bsp", "maps/%s.cm", "maps/%s.hmp", /*"maps/%s.map",*/ "maps/%s.bsp.gz", "maps/%s.bsp.xz", NULL}, *e;
int depth, bestdepth;
char *exts[] = {"%s", "maps/%s", "maps/%s.bsp", "maps/%s.cm", "maps/%s.hmp", /*"maps/%s.map",*/ "maps/%s.bsp.gz", "maps/%s.bsp.xz", NULL}, *e;
int depth, bestdepth = FDEPTH_MISSING;
flocation_t loc;
time_t filetime;
Q_snprintfz (sv.modelname, sizeof(sv.modelname), "%s", server);
bestdepth = COM_FDepthFile(sv.modelname, false);
char *mod = NULL;
if (bestdepth == FDEPTH_MISSING)
{ //not an exact name, scan the maps subdir.
for (i = 0; exts[i]; i++)
@ -1034,6 +1033,32 @@ void SV_SpawnServer (const char *server, const char *startspot, qboolean noents,
}
}
}
if (bestdepth == FDEPTH_MISSING)
{
mod = strchr(server, '#');
if (mod)
{
*mod = 0;
bestdepth = COM_FDepthFile(server, false);
if (bestdepth != FDEPTH_MISSING)
Q_snprintfz (sv.modelname, sizeof(sv.modelname), "%s", server);
else
{ //not an exact name, scan the maps subdir.
for (i = 0; exts[i]; i++)
{
depth = COM_FDepthFile(va(exts[i], server), false);
if (depth < bestdepth)
{
bestdepth = depth;
Q_snprintfz (sv.modelname, sizeof(sv.modelname), exts[i], server);
}
}
}
*mod = '#';
if (bestdepth == FDEPTH_MISSING)
mod = NULL;
}
}
if (!strncmp(sv.modelname, "maps/", 5))
Q_strncpyz (svs.name, sv.modelname+5, sizeof(svs.name));
@ -1048,6 +1073,8 @@ void SV_SpawnServer (const char *server, const char *startspot, qboolean noents,
if (!strcmp(e, ".bsp"))
*e = 0;
Mod_SetModifier(mod);
sv.world.worldmodel = Mod_ForName (sv.modelname, MLV_ERROR);
if (FS_FLocateFile(sv.modelname,FSLF_IFFOUND, &loc) && FS_GetLocMTime(&loc, &filetime))