From: havoc Date: Mon, 10 May 2010 06:29:56 +0000 (+0000) Subject: fixed bug with effectinfo.txt loading so that it now loads the proper X-Git-Tag: xonotic-v0.1.0preview~230^2~293 X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=commitdiff_plain;h=ef9fefb7ab57b0bfe6c159b75ea905db519c7cdd fixed bug with effectinfo.txt loading so that it now loads the proper name for the map added cl.worldmessage, cl.worldname, cl.worldbasename, cl.worldnamenoextension strings (and sv. versions) as well as cvars audited all use of these variables in the engine for consistent behavior basename generation for maps now strips only maps/ prefix (allowing subdirectory paths to be preserved) git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@10185 d7cf8633-e32d-0410-b094-e92efae38249 --- diff --git a/cl_main.c b/cl_main.c index b6c293c0..7d0a5f28 100644 --- a/cl_main.c +++ b/cl_main.c @@ -2106,8 +2106,7 @@ void CL_Locs_Save_f(void) Con_Printf("No level loaded!\n"); return; } - FS_StripExtension(cl.worldmodel->name, locfilename, sizeof(locfilename)); - strlcat(locfilename, ".loc", sizeof(locfilename)); + dpsnprintf(locfilename, sizeof(locfilename), "%s.loc", cl.worldnamenoextension); outfile = FS_OpenRealFile(locfilename, "w", false); if (!outfile) @@ -2184,14 +2183,12 @@ void CL_Locs_Reload_f(void) CL_Locs_Clear_f(); // try maps/something.loc first (LordHavoc: where I think they should be) - FS_StripExtension(cl.worldmodel->name, locfilename, sizeof(locfilename)); - strlcat(locfilename, ".loc", sizeof(locfilename)); + dpsnprintf(locfilename, sizeof(locfilename), "%s.loc", cl.worldnamenoextension); filedata = (char *)FS_LoadFile(locfilename, cls.levelmempool, false, &filesize); if (!filedata) { // try proquake name as well (LordHavoc: I hate path mangling) - FS_StripExtension(va("locs/%s", FS_FileWithoutPath(cl.worldmodel->name)), locfilename, sizeof(locfilename)); - strlcat(locfilename, ".loc", sizeof(locfilename)); + dpsnprintf(locfilename, sizeof(locfilename), "locs/%s.loc", cl.worldbasename); filedata = (char *)FS_LoadFile(locfilename, cls.levelmempool, false, &filesize); if (!filedata) return; diff --git a/cl_parse.c b/cl_parse.c index 63d49ab3..93b8837d 100644 --- a/cl_parse.c +++ b/cl_parse.c @@ -160,6 +160,11 @@ char *qw_svc_strings[128] = //============================================================================= +cvar_t cl_worldmessage = {CVAR_READONLY, "cl_worldmessage", "", "title of current level"}; +cvar_t cl_worldname = {CVAR_READONLY, "cl_worldname", "", "name of current worldmodel"}; +cvar_t cl_worldnamenoextension = {CVAR_READONLY, "cl_worldnamenoextension", "", "name of current worldmodel without extension"}; +cvar_t cl_worldbasename = {CVAR_READONLY, "cl_worldbasename", "", "name of current worldmodel without maps/ prefix or extension"}; + cvar_t demo_nehahra = {0, "demo_nehahra", "0", "reads all quake demos as nehahra movie protocol"}; cvar_t developer_networkentities = {0, "developer_networkentities", "0", "prints received entities, value is 0-4 (higher for more info)"}; cvar_t cl_gameplayfix_soundsmovewithentities = {0, "cl_gameplayfix_soundsmovewithentities", "1", "causes sounds made by lifts, players, projectiles, and any other entities, to move with the entity, so for example a rocket noise follows the rocket rather than staying at the starting position"}; @@ -441,11 +446,26 @@ static void CL_SetupWorldModel(void) cl.entities[0].render.model = cl.worldmodel = CL_GetModelByIndex(1); CL_UpdateRenderEntity(&cl.entities[0].render); + // make sure the cl.worldname and related cvars are set up now that we know the world model name // set up csqc world for collision culling if (cl.worldmodel) - World_SetSize(&cl.world, cl.worldmodel->name, cl.worldmodel->normalmins, cl.worldmodel->normalmaxs); + { + strlcpy(cl.worldname, cl.worldmodel->name, sizeof(cl.worldname)); + FS_StripExtension(cl.worldname, cl.worldnamenoextension, sizeof(cl.worldnamenoextension)); + strlcpy(cl.worldbasename, !strncmp(cl.worldnamenoextension, "maps/") ? cl.worldnamenoextension + 4 : cl.worldnamenoextension, sizeof(cl.worldbasename)); + Cvar_SetQuick(&cl_worldmessage, cl.worldmessage); + Cvar_SetQuick(&cl_worldname, cl.worldname); + Cvar_SetQuick(&cl_worldnamenoextension, cl.worldnamenoextension); + Cvar_SetQuick(&cl_worldbasename, cl.worldbasename); + World_SetSize(&cl.world, cl.worldname, cl.worldmodel->normalmins, cl.worldmodel->normalmaxs); + } else + { + Cvar_SetQuick(&cl_worldmessage, cl.worldmessage); + Cvar_SetQuick(&cl_worldnamenoextension, ""); + Cvar_SetQuick(&cl_worldbasename, ""); World_SetSize(&cl.world, "", defaultmins, defaultmaxs); + } World_Start(&cl.world); // load or reload .loc file for team chat messages @@ -1660,7 +1680,7 @@ void CL_ParseServerInfo (void) // get the full level name str = MSG_ReadString (); - strlcpy (cl.levelname, str, sizeof(cl.levelname)); + strlcpy (cl.worldmessage, str, sizeof(cl.worldmessage)); // get the movevars that are defined in the qw protocol cl.movevars_gravity = MSG_ReadFloat(); @@ -1705,6 +1725,17 @@ void CL_ParseServerInfo (void) // note: on QW protocol we can't set up the gameworld until after // downloads finish... // (we don't even know the name of the map yet) + // this also means cl_autodemo does not work on QW protocol... + + strlcpy(cl.worldname, "", sizeof(cl.worldname)); + strlcpy(cl.worldnamenoextension, "", sizeof(cl.worldnamenoextension)); + strlcpy(cl.worldbasename, "qw", sizeof(cl.worldbasename)); + Cvar_SetQuick(&cl_worldname, cl.worldname); + Cvar_SetQuick(&cl_worldnamenoextension, cl.worldnamenoextension); + Cvar_SetQuick(&cl_worldbasename, cl.worldbasename); + + // check memory integrity + Mem_CheckSentinelsGlobal(); } else { @@ -1726,7 +1757,7 @@ void CL_ParseServerInfo (void) // parse signon message str = MSG_ReadString (); - strlcpy (cl.levelname, str, sizeof(cl.levelname)); + strlcpy (cl.worldmessage, str, sizeof(cl.worldmessage)); // seperate the printfs so the server message can have a color if (cls.protocol != PROTOCOL_NEHAHRAMOVIE) // no messages when playing the Nehahra movie @@ -1760,6 +1791,15 @@ void CL_ParseServerInfo (void) strlcpy (cl.sound_name[numsounds], str, sizeof (cl.sound_name[numsounds])); } + // set the base name for level-specific things... this gets updated again by CL_SetupWorldModel later + strlcpy(cl.worldname, cl.model_name[1], sizeof(cl.worldname)); + FS_StripExtension(cl.worldname, cl.worldnamenoextension, sizeof(cl.worldnamenoextension)); + strlcpy(cl.worldbasename, FS_FileWithoutPath(cl.worldnamenoextension), sizeof(cl.worldbasename)); + Cvar_SetQuick(&cl_worldmessage, cl.worldmessage); + Cvar_SetQuick(&cl_worldname, cl.worldname); + Cvar_SetQuick(&cl_worldnamenoextension, cl.worldnamenoextension); + Cvar_SetQuick(&cl_worldbasename, cl.worldbasename); + // touch all of the precached models that are still loaded so we can free // anything that isn't needed if (!sv.active) @@ -1803,50 +1843,46 @@ void CL_ParseServerInfo (void) cl.loadbegun = false; cl.loadfinished = false; cl.loadcsqc = true; - } - - // check memory integrity - Mem_CheckSentinelsGlobal(); -// if cl_autodemo is set, automatically start recording a demo if one isn't being recorded already - if (cl_autodemo.integer && cls.netcon && cls.protocol != PROTOCOL_QUAKEWORLD) - { - char demofile[MAX_OSPATH]; - char levelname[MAX_QPATH]; + // check memory integrity + Mem_CheckSentinelsGlobal(); - if (cls.demorecording) + // if cl_autodemo is set, automatically start recording a demo if one isn't being recorded already + if (cl_autodemo.integer && cls.netcon && cls.protocol != PROTOCOL_QUAKEWORLD) { - // finish the previous level's demo file - CL_Stop_f(); - } + char demofile[MAX_OSPATH]; - // start a new demo file - strlcpy(levelname, FS_FileWithoutPath(cl.model_name[1]), sizeof(levelname)); - if (strrchr(levelname, '.')) - *(strrchr(levelname, '.')) = 0; - dpsnprintf (demofile, sizeof(demofile), "%s_%s.dem", Sys_TimeString (cl_autodemo_nameformat.string), levelname); + if (cls.demorecording) + { + // finish the previous level's demo file + CL_Stop_f(); + } - Con_Printf ("Auto-recording to %s.\n", demofile); + // start a new demo file + dpsnprintf (demofile, sizeof(demofile), "%s_%s.dem", Sys_TimeString (cl_autodemo_nameformat.string), cl.worldbasename); - // Reset bit 0 for every new demo - Cvar_SetValueQuick(&cl_autodemo_delete, - (cl_autodemo_delete.integer & ~0x1) - | - ((cl_autodemo_delete.integer & 0x2) ? 0x1 : 0) - ); + Con_Printf ("Auto-recording to %s.\n", demofile); - cls.demofile = FS_OpenRealFile(demofile, "wb", false); - if (cls.demofile) - { - cls.forcetrack = -1; - FS_Printf (cls.demofile, "%i\n", cls.forcetrack); - cls.demorecording = true; - strlcpy(cls.demoname, demofile, sizeof(cls.demoname)); - cls.demo_lastcsprogssize = -1; - cls.demo_lastcsprogscrc = -1; + // Reset bit 0 for every new demo + Cvar_SetValueQuick(&cl_autodemo_delete, + (cl_autodemo_delete.integer & ~0x1) + | + ((cl_autodemo_delete.integer & 0x2) ? 0x1 : 0) + ); + + cls.demofile = FS_OpenRealFile(demofile, "wb", false); + if (cls.demofile) + { + cls.forcetrack = -1; + FS_Printf (cls.demofile, "%i\n", cls.forcetrack); + cls.demorecording = true; + strlcpy(cls.demoname, demofile, sizeof(cls.demoname)); + cls.demo_lastcsprogssize = -1; + cls.demo_lastcsprogscrc = -1; + } + else + Con_Print ("ERROR: couldn't open.\n"); } - else - Con_Print ("ERROR: couldn't open.\n"); } } @@ -4135,6 +4171,11 @@ void CL_Parse_ErrorCleanUp(void) void CL_Parse_Init(void) { + Cvar_RegisterVariable(&cl_worldmessage); + Cvar_RegisterVariable(&cl_worldname); + Cvar_RegisterVariable(&cl_worldnamenoextension); + Cvar_RegisterVariable(&cl_worldbasename); + // LordHavoc: added demo_nehahra cvar Cvar_RegisterVariable (&demo_nehahra); if (gamemode == GAME_NEHAHRA) diff --git a/cl_particles.c b/cl_particles.c index a5b987ea..c33df7ba 100644 --- a/cl_particles.c +++ b/cl_particles.c @@ -480,7 +480,11 @@ void CL_Particles_LoadEffectInfo(void) if (filepass == 0) dpsnprintf(filename, sizeof(filename), "effectinfo.txt"); else if (filepass == 1) - dpsnprintf(filename, sizeof(filename), "maps/%s_effectinfo.txt", cl.levelname); + { + if (!cl.worldbasename[0]) + continue; + dpsnprintf(filename, sizeof(filename), "%s_effectinfo.txt", cl.worldnamenoextension); + } else break; filedata = FS_LoadFile(filename, tempmempool, true, &filesize); @@ -1520,13 +1524,12 @@ void CL_ReadPointFile_f (void) vec3_t org, leakorg; int r, c, s; char *pointfile = NULL, *pointfilepos, *t, tchar; - char name[MAX_OSPATH]; + char name[MAX_QPATH]; if (!cl.worldmodel) return; - FS_StripExtension (cl.worldmodel->name, name, sizeof (name)); - strlcat (name, ".pts", sizeof (name)); + dpsnprintf(name, sizeof(name), "%s.pts", cl.worldnamenoextension); pointfile = (char *)FS_LoadFile(name, tempmempool, true, NULL); if (!pointfile) { diff --git a/cl_screen.c b/cl_screen.c index 76be67dc..4121ae39 100644 --- a/cl_screen.c +++ b/cl_screen.c @@ -925,7 +925,6 @@ void SCR_ScreenShot_f (void) static char old_prefix_name[MAX_QPATH]; char prefix_name[MAX_QPATH]; char filename[MAX_QPATH]; - char mapname[MAX_QPATH]; unsigned char *buffer1; unsigned char *buffer2; qboolean jpeg = (scr_screenshot_jpeg.integer != 0); @@ -960,15 +959,10 @@ void SCR_ScreenShot_f (void) else { // TODO maybe make capturevideo and screenshot use similar name patterns? - if (scr_screenshot_name_in_mapdir.integer && cl.worldmodel && *cl.worldmodel->name) { - // figure out the map's filename without path or extension - strlcpy(mapname, FS_FileWithoutPath(cl.worldmodel->name), sizeof(mapname)); - if (strrchr(mapname, '.')) - *(strrchr(mapname, '.')) = 0; - dpsnprintf (prefix_name, sizeof(prefix_name), "%s/%s", mapname, Sys_TimeString(scr_screenshot_name.string)); - } else { + if (scr_screenshot_name_in_mapdir.integer && cl.worldbasename[0]) + dpsnprintf (prefix_name, sizeof(prefix_name), "%s/%s", cl.worldbasename, Sys_TimeString(scr_screenshot_name.string)); + else dpsnprintf (prefix_name, sizeof(prefix_name), "%s", Sys_TimeString(scr_screenshot_name.string)); - } if (strcmp(old_prefix_name, prefix_name)) { diff --git a/client.h b/client.h index 3a7b6939..3ed504a3 100644 --- a/client.h +++ b/client.h @@ -1011,7 +1011,11 @@ typedef struct client_state_s char sound_name[MAX_SOUNDS][MAX_QPATH]; // for display on solo scoreboard - char levelname[40]; + char worldmessage[40]; // map title (not related to filename) + // variants of map name + char worldbasename[MAX_QPATH]; // %s + char worldname[MAX_QPATH]; // maps/%s.bsp + char worldnamenoextension[MAX_QPATH]; // maps/%s // cl_entitites[cl.viewentity] = player int viewentity; // the real player entity (normally same as viewentity, diff --git a/csprogs.c b/csprogs.c index bdb0e485..d417fa97 100644 --- a/csprogs.c +++ b/csprogs.c @@ -976,13 +976,13 @@ void CL_VM_Init (void) prog->globals.client->time = cl.time; prog->globals.client->self = 0; - prog->globals.client->mapname = cl.worldmodel ? PRVM_SetEngineString(cl.worldmodel->name) : PRVM_SetEngineString(""); + prog->globals.client->mapname = PRVM_SetEngineString(cl.worldname); prog->globals.client->player_localentnum = cl.playerentity; // set map description (use world entity 0) val = PRVM_EDICTFIELDVALUE(prog->edicts, prog->fieldoffsets.message); if(val) - val->string = PRVM_SetEngineString(cl.levelname); + val->string = PRVM_SetEngineString(cl.worldmessage); VectorCopy(cl.world.mins, prog->edicts->fields.client->mins); VectorCopy(cl.world.maxs, prog->edicts->fields.client->maxs); diff --git a/gl_rmain.c b/gl_rmain.c index 2ae129dc..d18c1a70 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -6297,7 +6297,6 @@ extern void CL_ParseEntityLump(char *entitystring); void gl_main_newmap(void) { // FIXME: move this code to client - int l; char *entities, entname[MAX_QPATH]; if (r_qwskincache) Mem_Free(r_qwskincache); @@ -6305,17 +6304,12 @@ void gl_main_newmap(void) r_qwskincache_size = 0; if (cl.worldmodel) { - strlcpy(entname, cl.worldmodel->name, sizeof(entname)); - l = (int)strlen(entname) - 4; - if (l >= 0 && !strcmp(entname + l, ".bsp")) + dpsnprintf(entname, sizeof(entname), "%s.ent", cl.worldnamenoextension); + if ((entities = (char *)FS_LoadFile(entname, tempmempool, true, NULL))) { - memcpy(entname + l, ".ent", 5); - if ((entities = (char *)FS_LoadFile(entname, tempmempool, true, NULL))) - { - CL_ParseEntityLump(entities); - Mem_Free(entities); - return; - } + CL_ParseEntityLump(entities); + Mem_Free(entities); + return; } if (cl.worldmodel->brush.entities) CL_ParseEntityLump(cl.worldmodel->brush.entities); diff --git a/host_cmd.c b/host_cmd.c index 24111c58..f341d7d6 100644 --- a/host_cmd.c +++ b/host_cmd.c @@ -999,7 +999,7 @@ void Host_Loadgame_f (void) if (i >= 0 && i < MAX_MODELS) { strlcpy(sv.model_precache[i], com_token, sizeof(sv.model_precache[i])); - sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, sv.model_precache[i][0] == '*' ? sv.modelname : NULL); + sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, sv.model_precache[i][0] == '*' ? sv.worldname : NULL); } else Con_Printf("unsupported model %i \"%s\"\n", i, com_token); diff --git a/netconn.c b/netconn.c index 2700ee4a..3f0796e5 100755 --- a/netconn.c +++ b/netconn.c @@ -2213,7 +2213,7 @@ static qboolean NetConn_BuildStatusResponse(const char* challenge, char* out_msg "%s", fullstatus ? "statusResponse" : "infoResponse", gamename, com_modname, gameversion.integer, svs.maxclients, - nb_clients, nb_bots, sv.name, hostname.string, NET_PROTOCOL_VERSION, + nb_clients, nb_bots, sv.worldbasename, hostname.string, NET_PROTOCOL_VERSION, *qcstatus ? "\\qcstatus\\" : "", qcstatus, challenge ? "\\challenge\\" : "", challenge ? challenge : "", fullstatus ? "\n" : ""); diff --git a/r_shadow.c b/r_shadow.c index 445d0dea..f546b146 100644 --- a/r_shadow.c +++ b/r_shadow.c @@ -666,7 +666,7 @@ void r_shadow_newmap(void) if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight); if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight); if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection); - if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname))) + if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname))) R_Shadow_EditLights_Reload_f(); } @@ -5001,8 +5001,7 @@ void R_Shadow_LoadWorldLights(void) Con_Print("No map loaded.\n"); return; } - FS_StripExtension (cl.worldmodel->name, name, sizeof (name)); - strlcat (name, ".rtlights", sizeof (name)); + dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension); lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL); if (lightsstring) { @@ -5112,8 +5111,7 @@ void R_Shadow_SaveWorldLights(void) Con_Print("No map loaded.\n"); return; } - FS_StripExtension (cl.worldmodel->name, name, sizeof (name)); - strlcat (name, ".rtlights", sizeof (name)); + dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension); bufchars = bufmaxchars = 0; buf = NULL; for (lightindex = 0;lightindex < range;lightindex++) @@ -5161,8 +5159,7 @@ void R_Shadow_LoadLightsFile(void) Con_Print("No map loaded.\n"); return; } - FS_StripExtension (cl.worldmodel->name, name, sizeof (name)); - strlcat (name, ".lights", sizeof (name)); + dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension); lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL); if (lightsstring) { @@ -5224,8 +5221,7 @@ void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void) return; } // try to load a .ent file first - FS_StripExtension (cl.worldmodel->name, key, sizeof (key)); - strlcat (key, ".ent", sizeof (key)); + dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension); data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL); // and if that is not found, fall back to the bsp file entity string if (!data) @@ -5474,7 +5470,7 @@ void R_Shadow_EditLights_Reload_f(void) { if (!cl.worldmodel) return; - strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname)); + strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname)); R_Shadow_ClearWorldLights(); R_Shadow_LoadWorldLights(); if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray)) diff --git a/sbar.c b/sbar.c index 81c72f8d..e4390b6b 100644 --- a/sbar.c +++ b/sbar.c @@ -684,14 +684,8 @@ void Sbar_SoloScoreboard (void) else if (cl.stats[STAT_SECRETS]) // LA: And similarly for secrets Sbar_DrawString(8+22*8, 4, va("Secrets:%3i", cl.stats[STAT_SECRETS])); - // figure out the map's filename without path or extension - strlcpy(str, FS_FileWithoutPath(cl.worldmodel ? cl.worldmodel->name : ""), sizeof(str)); - if (strrchr(str, '.')) - *(strrchr(str, '.')) = 0; - - // append a : separator and then the full title - strlcat(str, ":", sizeof(str)); - strlcat(str, cl.levelname, sizeof(str)); + // format is like this: e1m1:The Sligpate Complex + dpsnprintf(str, sizeof(str), "%s:%s", cl.worldbasename, cl.worldmessage); // if there's a newline character, terminate the string there if (strchr(str, '\n')) @@ -734,11 +728,11 @@ void Sbar_SoloScoreboard (void) // draw level name if (gamemode == GAME_NEXUIZ) { - l = (int) strlen (cl.worldmodel->name); - Sbar_DrawString (232 - l*4, 12, cl.worldmodel->name); + l = (int) strlen (cl.worldname); + Sbar_DrawString (232 - l*4, 12, cl.worldname); } else { - l = (int) strlen (cl.levelname); - Sbar_DrawString (232 - l*4, 12, cl.levelname); + l = (int) strlen (cl.worldmessage); + Sbar_DrawString (232 - l*4, 12, cl.worldmessage); } #endif } diff --git a/server.h b/server.h index ad15e21f..fdea1076 100644 --- a/server.h +++ b/server.h @@ -98,9 +98,12 @@ typedef struct server_s world_t world; /// map name - char name[64]; - /// maps/.bsp, for model_precache[0] - char modelname[64]; + char name[64]; // %s followed by entrance name + // variants of map name + char worldmessage[40]; // map title (not related to filename) + char worldbasename[MAX_QPATH]; // %s + char worldname[MAX_QPATH]; // maps/%s.bsp + char worldnamenoextension[MAX_QPATH]; // maps/%s struct model_s *worldmodel; // NULL terminated // LordHavoc: precaches are now MAX_QPATH rather than a pointer diff --git a/sv_main.c b/sv_main.c index 60f2dbe8..69e6b065 100644 --- a/sv_main.c +++ b/sv_main.c @@ -33,6 +33,11 @@ extern cvar_t net_connecttimeout; void VM_CustomStats_Clear (void); void VM_SV_UpdateCustomStats (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats); +cvar_t sv_worldmessage = {CVAR_READONLY, "sv_worldmessage", "", "title of current level"}; +cvar_t sv_worldname = {CVAR_READONLY, "sv_worldname", "", "name of current worldmodel"}; +cvar_t sv_worldnamenoextension = {CVAR_READONLY, "sv_worldnamenoextension", "", "name of current worldmodel without extension"}; +cvar_t sv_worldbasename = {CVAR_READONLY, "sv_worldbasename", "", "name of current worldmodel without maps/ prefix or extension"}; + cvar_t coop = {0, "coop","0", "coop mode, 0 = no coop, 1 = coop mode, multiple players playing through the singleplayer game (coop mode also shuts off deathmatch)"}; cvar_t deathmatch = {0, "deathmatch","0", "deathmatch mode, values depend on mod but typically 0 = no deathmatch, 1 = normal deathmatch with respawning weapons, 2 = weapons stay (players can only pick up new weapons)"}; cvar_t fraglimit = {CVAR_NOTIFY, "fraglimit","0", "ends level if this many frags is reached by any player"}; @@ -340,6 +345,12 @@ void SV_Init (void) extern cvar_t csqc_progname; //[515]: csqc crc check and right csprogs name according to progs.dat extern cvar_t csqc_progcrc; extern cvar_t csqc_progsize; + + Cvar_RegisterVariable(&sv_worldmessage); + Cvar_RegisterVariable(&sv_worldname); + Cvar_RegisterVariable(&sv_worldnamenoextension); + Cvar_RegisterVariable(&sv_worldbasename); + Cvar_RegisterVariable (&csqc_progname); Cvar_RegisterVariable (&csqc_progcrc); Cvar_RegisterVariable (&csqc_progsize); @@ -531,14 +542,12 @@ void SV_Init (void) static void SV_SaveEntFile_f(void) { - char basename[MAX_QPATH]; if (!sv.active || !sv.worldmodel) { Con_Print("Not running a server\n"); return; } - FS_StripExtension(sv.worldmodel->name, basename, sizeof(basename)); - FS_WriteFile(va("%s.ent", basename), sv.worldmodel->brush.entities, (fs_offset_t)strlen(sv.worldmodel->brush.entities)); + FS_WriteFile(va("%s.ent", sv.worldnamenoextension), sv.worldmodel->brush.entities, (fs_offset_t)strlen(sv.worldmodel->brush.entities)); } @@ -835,20 +844,15 @@ void SV_SendServerinfo (client_t *client) if(sv_autodemo_perclient.integer && client->netconnection) { char demofile[MAX_OSPATH]; - char levelname[MAX_QPATH]; char ipaddress[MAX_QPATH]; size_t i; // start a new demo file - strlcpy(levelname, FS_FileWithoutPath(sv.worldmodel->name), sizeof(levelname)); - if (strrchr(levelname, '.')) - *(strrchr(levelname, '.')) = 0; - LHNETADDRESS_ToString(&(client->netconnection->peeraddress), ipaddress, sizeof(ipaddress), true); for(i = 0; ipaddress[i]; ++i) if(!isalnum(ipaddress[i])) ipaddress[i] = '-'; - dpsnprintf (demofile, sizeof(demofile), "%s_%s_%d_%s.dem", Sys_TimeString (sv_autodemo_perclient_nameformat.string), levelname, PRVM_NUM_FOR_EDICT(client->edict), ipaddress); + dpsnprintf (demofile, sizeof(demofile), "%s_%s_%d_%s.dem", Sys_TimeString (sv_autodemo_perclient_nameformat.string), sv.worldbasename, PRVM_NUM_FOR_EDICT(client->edict), ipaddress); SV_StartDemoRecording(client, demofile, -1); } @@ -2718,7 +2722,7 @@ int SV_ModelIndex(const char *s, int precachemode) if (precachemode == 1) Con_Printf("SV_ModelIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename); strlcpy(sv.model_precache[i], filename, sizeof(sv.model_precache[i])); - sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, s[0] == '*' ? sv.modelname : NULL); + sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, s[0] == '*' ? sv.worldname : NULL); if (sv.state != ss_loading) { MSG_WriteByte(&sv.reliable_datagram, svc_precache); @@ -2813,7 +2817,7 @@ int SV_ParticleEffectIndex(const char *name) if (filepass == 0) dpsnprintf(filename, sizeof(filename), "effectinfo.txt"); else if (filepass == 1) - dpsnprintf(filename, sizeof(filename), "maps/%s_effectinfo.txt", sv.name); + dpsnprintf(filename, sizeof(filename), "%s_effectinfo.txt", sv.worldnamenoextension); else break; filedata = FS_LoadFile(filename, tempmempool, true, &filesize); @@ -3061,7 +3065,7 @@ void SV_SpawnServer (const char *server) int i; char *entities; dp_model_t *worldmodel; - char modelname[sizeof(sv.modelname)]; + char modelname[sizeof(sv.worldname)]; Con_DPrintf("SpawnServer: %s\n", server); @@ -3164,7 +3168,15 @@ void SV_SpawnServer (const char *server) sv.active = true; + // set level base name variables for later use strlcpy (sv.name, server, sizeof (sv.name)); + strlcpy(sv.worldname, modelname, sizeof(sv.worldname)); + FS_StripExtension(sv.worldname, sv.worldnamenoextension, sizeof(sv.worldnamenoextension)); + strlcpy(sv.worldbasename, !strncmp(sv.worldnamenoextension, "maps/") ? sv.worldnamenoextension + 4 : sv.worldnamenoextension, sizeof(sv.worldbasename)); + //Cvar_SetQuick(&sv_worldmessage, sv.worldmessage); // set later after QC is spawned + Cvar_SetQuick(&sv_worldname, sv.worldname); + Cvar_SetQuick(&sv_worldnamenoextension, sv.worldnamenoextension); + Cvar_SetQuick(&sv_worldbasename, sv.worldbasename); sv.protocol = Protocol_EnumForName(sv_protocolname.string); if (sv.protocol == PROTOCOL_UNKNOWN) @@ -3204,25 +3216,23 @@ void SV_SpawnServer (const char *server) Mod_ClearUsed(); worldmodel->used = true; - strlcpy (sv.name, server, sizeof (sv.name)); - strlcpy(sv.modelname, modelname, sizeof(sv.modelname)); sv.worldmodel = worldmodel; sv.models[1] = sv.worldmodel; // // clear world interaction links // - World_SetSize(&sv.world, sv.worldmodel->name, sv.worldmodel->normalmins, sv.worldmodel->normalmaxs); + World_SetSize(&sv.world, sv.worldname, sv.worldmodel->normalmins, sv.worldmodel->normalmaxs); World_Start(&sv.world); strlcpy(sv.sound_precache[0], "", sizeof(sv.sound_precache[0])); strlcpy(sv.model_precache[0], "", sizeof(sv.model_precache[0])); - strlcpy(sv.model_precache[1], sv.modelname, sizeof(sv.model_precache[1])); + strlcpy(sv.model_precache[1], sv.worldname, sizeof(sv.model_precache[1])); for (i = 1;i < sv.worldmodel->brush.numsubmodels && i+1 < MAX_MODELS;i++) { dpsnprintf(sv.model_precache[i+1], sizeof(sv.model_precache[i+1]), "*%i", i); - sv.models[i+1] = Mod_ForName (sv.model_precache[i+1], false, false, sv.modelname); + sv.models[i+1] = Mod_ForName (sv.model_precache[i+1], false, false, sv.worldname); } if(i < sv.worldmodel->brush.numsubmodels) Con_Printf("Too many submodels (MAX_MODELS is %i)\n", MAX_MODELS); @@ -3234,7 +3244,7 @@ void SV_SpawnServer (const char *server) ent = PRVM_EDICT_NUM(0); memset (ent->fields.server, 0, prog->progs->entityfields * 4); ent->priv.server->free = false; - ent->fields.server->model = PRVM_SetEngineString(sv.modelname); + ent->fields.server->model = PRVM_SetEngineString(sv.worldname); ent->fields.server->modelindex = 1; // world model ent->fields.server->solid = SOLID_BSP; ent->fields.server->movetype = MOVETYPE_PUSH; @@ -3265,9 +3275,9 @@ void SV_SpawnServer (const char *server) } // load replacement entity file if found - if (sv_entpatch.integer && (entities = (char *)FS_LoadFile(va("maps/%s.ent", sv.name), tempmempool, true, NULL))) + if (sv_entpatch.integer && (entities = (char *)FS_LoadFile(va("%s.ent", sv.worldnamenoextension), tempmempool, true, NULL))) { - Con_Printf("Loaded maps/%s.ent\n", sv.name); + Con_Printf("Loaded %s.ent\n", sv.worldnamenoextension); PRVM_ED_LoadFromFile (entities); Mem_Free(entities); } @@ -3330,6 +3340,10 @@ void SV_SpawnServer (const char *server) } } + // update the map title cvar + strlcpy(sv.worldmessage, PRVM_GetString(prog->edicts->fields.server->message), sizeof(sv.worldmessage)); // map title (not related to filename) + Cvar_SetQuick(&sv_worldmessage, sv.worldmessage); + Con_DPrint("Server spawned.\n"); NetConn_Heartbeat (2);