X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=sv_main.c;h=74bef76b39122ed27614da8051b95232812c1200;hb=321a67123284c38c22f8edd418913615ee0c2682;hp=74737a83e6e1c43f8cb91552a678a44c8841b411;hpb=553d6dc6bd8b263d6ed3fe5ca992bd95bf48dd6b;p=xonotic%2Fdarkplaces.git diff --git a/sv_main.c b/sv_main.c index 74737a83..74bef76b 100644 --- a/sv_main.c +++ b/sv_main.c @@ -27,7 +27,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. static void SV_SaveEntFile_f(void); static void SV_StartDownload_f(void); static void SV_Download_f(void); -static void SV_VM_Setup(); +static void SV_VM_Setup(void); extern cvar_t net_connecttimeout; void VM_CustomStats_Clear (void); @@ -50,6 +50,10 @@ cvar_t sv_aim = {CVAR_SAVE, "sv_aim", "2", "maximum cosine angle for quake's ver cvar_t sv_airaccel_qw = {0, "sv_airaccel_qw", "1", "ratio of QW-style air control as opposed to simple acceleration"}; cvar_t sv_airaccel_sideways_friction = {0, "sv_airaccel_sideways_friction", "", "anti-sideways movement stabilization (reduces speed gain when zigzagging)"}; cvar_t sv_airaccelerate = {0, "sv_airaccelerate", "-1", "rate at which a player accelerates to sv_maxairspeed while in the air, if less than 0 the sv_accelerate variable is used instead"}; +cvar_t sv_airstopaccelerate = {0, "sv_airstopaccelerate", "0", "when set, replacement for sv_airaccelerate when moving backwards"}; +cvar_t sv_airstrafeaccelerate = {0, "sv_airstrafeaccelerate", "0", "when set, replacement for sv_airaccelerate when just strafing"}; +cvar_t sv_maxairstrafespeed = {0, "sv_maxairstrafespeed", "0", "when set, replacement for sv_maxairspeed when just strafing"}; +cvar_t sv_aircontrol = {0, "sv_aircontrol", "0", "CPMA-style air control"}; cvar_t sv_allowdownloads = {0, "sv_allowdownloads", "1", "whether to allow clients to download files from the server (does not affect http downloads)"}; cvar_t sv_allowdownloads_archive = {0, "sv_allowdownloads_archive", "0", "whether to allow downloads of archives (pak/pk3)"}; cvar_t sv_allowdownloads_config = {0, "sv_allowdownloads_config", "0", "whether to allow downloads of config files (cfg)"}; @@ -59,8 +63,9 @@ cvar_t sv_areagrid_mingridsize = {CVAR_NOTIFY, "sv_areagrid_mingridsize", "64", cvar_t sv_checkforpacketsduringsleep = {0, "sv_checkforpacketsduringsleep", "0", "uses select() function to wait between frames which can be interrupted by packets being received, instead of Sleep()/usleep()/SDL_Sleep() functions which do not check for packets"}; cvar_t sv_clmovement_enable = {0, "sv_clmovement_enable", "1", "whether to allow clients to use cl_movement prediction, which can cause choppy movement on the server which may annoy other players"}; cvar_t sv_clmovement_minping = {0, "sv_clmovement_minping", "0", "if client ping is below this time in milliseconds, then their ability to use cl_movement prediction is disabled for a while (as they don't need it)"}; +cvar_t sv_clmovement_maxnetfps = {0, "sv_clmovement_maxnetfps", "0", "max amount of movement packets to accept per second"}; cvar_t sv_clmovement_minping_disabletime = {0, "sv_clmovement_minping_disabletime", "1000", "when client falls below minping, disable their prediction for this many milliseconds (should be at least 1000 or else their prediction may turn on/off frequently)"}; -cvar_t sv_clmovement_waitforinput = {0, "sv_clmovement_waitforinput", "4", "when a client does not send input for this many frames, force them to move anyway (unlike QuakeWorld)"}; +cvar_t sv_clmovement_inputtimeout = {0, "sv_clmovement_inputtimeout", "0.2", "when a client does not send input for this many seconds, force them to move anyway (unlike QuakeWorld)"}; cvar_t sv_cullentities_nevercullbmodels = {0, "sv_cullentities_nevercullbmodels", "0", "if enabled the clients are always notified of moving doors and lifts and other submodels of world (warning: eats a lot of network bandwidth on some levels!)"}; cvar_t sv_cullentities_pvs = {0, "sv_cullentities_pvs", "1", "fast but loose culling of hidden entities"}; cvar_t sv_cullentities_stats = {0, "sv_cullentities_stats", "0", "displays stats on network entities culled by various methods for each client"}; @@ -87,6 +92,7 @@ cvar_t sv_gameplayfix_easierwaterjump = {0, "sv_gameplayfix_easierwaterjump", "1 cvar_t sv_gameplayfix_findradiusdistancetobox = {0, "sv_gameplayfix_findradiusdistancetobox", "1", "causes findradius to check the distance to the corner of a box rather than the center of the box, makes findradius detect bmodels such as very large doors that would otherwise be unaffected by splash damage"}; cvar_t sv_gameplayfix_grenadebouncedownslopes = {0, "sv_gameplayfix_grenadebouncedownslopes", "1", "prevents MOVETYPE_BOUNCE (grenades) from getting stuck when fired down a downward sloping surface"}; cvar_t sv_gameplayfix_multiplethinksperframe = {0, "sv_gameplayfix_multiplethinksperframe", "1", "allows entities to think more often than the server framerate, primarily useful for very high fire rate weapons"}; +cvar_t sv_gameplayfix_slidemoveprojectiles = {0, "sv_gameplayfix_slidemoveprojectiles", "1", "allows MOVETYPE_FLY/FLYMISSILE/TOSS/BOUNCE/BOUNCEMISSILE entities to finish their move in a frame even if they hit something, fixes 'gravity accumulation' bug for grenades on steep slopes"}; cvar_t sv_gameplayfix_noairborncorpse = {0, "sv_gameplayfix_noairborncorpse", "1", "causes entities (corpses) sitting ontop of moving entities (players) to fall when the moving entity (player) is no longer supporting them"}; cvar_t sv_gameplayfix_setmodelrealbox = {0, "sv_gameplayfix_setmodelrealbox", "1", "fixes a bug in Quake that made setmodel always set the entity box to ('-16 -16 -16', '16 16 16') rather than properly checking the model box, breaks some poorly coded mods"}; cvar_t sv_gameplayfix_stepdown = {0, "sv_gameplayfix_stepdown", "0", "attempts to step down stairs, not just up them (prevents the familiar thud..thud..thud.. when running down stairs and slopes)"}; @@ -116,6 +122,11 @@ cvar_t sv_stopspeed = {CVAR_NOTIFY, "sv_stopspeed","100", "how fast you come to cvar_t sv_wallfriction = {CVAR_NOTIFY, "sv_wallfriction", "1", "how much you slow down when sliding along a wall"}; cvar_t sv_wateraccelerate = {0, "sv_wateraccelerate", "-1", "rate at which a player accelerates to sv_maxspeed while in the air, if less than 0 the sv_accelerate variable is used instead"}; cvar_t sv_waterfriction = {CVAR_NOTIFY, "sv_waterfriction","-1", "how fast you slow down, if less than 0 the sv_friction variable is used instead"}; +cvar_t sv_warsowbunny_airforwardaccel = {0, "sv_warsowbunny_airforwardaccel", "1.00001", "how fast you accelerate until you reach sv_maxspeed"}; +cvar_t sv_warsowbunny_accel = {0, "sv_warsowbunny_accel", "0.1585", "how fast you accelerate until after reaching sv_maxspeed (it gets harder as you near sv_warsowbunny_topspeed)"}; +cvar_t sv_warsowbunny_topspeed = {0, "sv_warsowbunny_topspeed", "925", "soft speed limit (can get faster with rjs and on ramps)"}; +cvar_t sv_warsowbunny_turnaccel = {0, "sv_warsowbunny_turnaccel", "0", "max sharpness of turns (also master switch for the sv_warsowbunny_* mode; set this to 9 to enable)"}; +cvar_t sv_warsowbunny_backtosideratio = {0, "sv_warsowbunny_backtosideratio", "0.8", "lower values make it easier to change direction without losing speed; the drawback is \"understeering\" in sharp turns"}; cvar_t sys_ticrate = {CVAR_SAVE, "sys_ticrate","0.0138889", "how long a server frame is in seconds, 0.05 is 20fps server rate, 0.1 is 10fps (can not be set higher than 0.1), 0 runs as many server frames as possible (makes games against bots a little smoother, overwhelms network players), 0.0138889 matches QuakeWorld physics"}; cvar_t teamplay = {CVAR_NOTIFY, "teamplay","0", "teamplay mode, values depend on mod but typically 0 = no teams, 1 = no team damage no self damage, 2 = team damage and self damage, some mods support 3 = no team damage but can damage self"}; cvar_t timelimit = {CVAR_NOTIFY, "timelimit","0", "ends level at this time (in minutes)"}; @@ -156,6 +167,7 @@ cvar_t cutscene = {0, "cutscene", "1", "enables cutscenes in nehahra, can be use cvar_t sv_autodemo_perclient = {CVAR_SAVE, "sv_autodemo_perclient", "0", "set to 1 to enable autorecorded per-client demos (they'll start to record at the beginning of a match); set it to 2 to also record client->server packets (for debugging)"}; cvar_t sv_autodemo_perclient_nameformat = {CVAR_SAVE, "sv_autodemo_perclient_nameformat", "sv_autodemos/%Y-%m-%d_%H-%M", "The format of the sv_autodemo_perclient filename, followed by the map name, the client number and the IP address + port number, separated by underscores (the date is encoded using strftime escapes)" }; +cvar_t halflifebsp = {0, "halflifebsp", "0", "indicates the current map is hlbsp format (useful to know because of different bounding box sizes)"}; server_t sv; server_static_t svs; @@ -326,6 +338,10 @@ void SV_Init (void) Cvar_RegisterVariable (&sv_airaccel_qw); Cvar_RegisterVariable (&sv_airaccel_sideways_friction); Cvar_RegisterVariable (&sv_airaccelerate); + Cvar_RegisterVariable (&sv_airstopaccelerate); + Cvar_RegisterVariable (&sv_airstrafeaccelerate); + Cvar_RegisterVariable (&sv_maxairstrafespeed); + Cvar_RegisterVariable (&sv_aircontrol); Cvar_RegisterVariable (&sv_allowdownloads); Cvar_RegisterVariable (&sv_allowdownloads_archive); Cvar_RegisterVariable (&sv_allowdownloads_config); @@ -334,9 +350,10 @@ void SV_Init (void) Cvar_RegisterVariable (&sv_areagrid_mingridsize); Cvar_RegisterVariable (&sv_checkforpacketsduringsleep); Cvar_RegisterVariable (&sv_clmovement_enable); + Cvar_RegisterVariable (&sv_clmovement_maxnetfps); Cvar_RegisterVariable (&sv_clmovement_minping); Cvar_RegisterVariable (&sv_clmovement_minping_disabletime); - Cvar_RegisterVariable (&sv_clmovement_waitforinput); + Cvar_RegisterVariable (&sv_clmovement_inputtimeout); Cvar_RegisterVariable (&sv_cullentities_nevercullbmodels); Cvar_RegisterVariable (&sv_cullentities_pvs); Cvar_RegisterVariable (&sv_cullentities_stats); @@ -363,6 +380,7 @@ void SV_Init (void) Cvar_RegisterVariable (&sv_gameplayfix_findradiusdistancetobox); Cvar_RegisterVariable (&sv_gameplayfix_grenadebouncedownslopes); Cvar_RegisterVariable (&sv_gameplayfix_multiplethinksperframe); + Cvar_RegisterVariable (&sv_gameplayfix_slidemoveprojectiles); Cvar_RegisterVariable (&sv_gameplayfix_noairborncorpse); Cvar_RegisterVariable (&sv_gameplayfix_setmodelrealbox); Cvar_RegisterVariable (&sv_gameplayfix_stepdown); @@ -392,6 +410,11 @@ void SV_Init (void) Cvar_RegisterVariable (&sv_wallfriction); Cvar_RegisterVariable (&sv_wateraccelerate); Cvar_RegisterVariable (&sv_waterfriction); + Cvar_RegisterVariable (&sv_warsowbunny_airforwardaccel); + Cvar_RegisterVariable (&sv_warsowbunny_accel); + Cvar_RegisterVariable (&sv_warsowbunny_topspeed); + Cvar_RegisterVariable (&sv_warsowbunny_turnaccel); + Cvar_RegisterVariable (&sv_warsowbunny_backtosideratio); Cvar_RegisterVariable (&sys_ticrate); Cvar_RegisterVariable (&teamplay); Cvar_RegisterVariable (&timelimit); @@ -436,13 +459,24 @@ void SV_Init (void) Cvar_RegisterVariable (&sv_autodemo_perclient); Cvar_RegisterVariable (&sv_autodemo_perclient_nameformat); + Cvar_RegisterVariable (&halflifebsp); + // any special defaults for gamemodes go here + if (gamemode == GAME_NEHAHRA) + { + // Nehahra pushable crates malfunction in some levels if this is on + Cvar_SetValueQuick (&sv_gameplayfix_upwardvelocityclearsongroundflag, 0); + // Nehahra NPC AI is confused by this feature + Cvar_SetValueQuick (&sv_gameplayfix_blowupfallenzombies, 0); + } if (gamemode == GAME_HIPNOTIC) { // hipnotic mission pack has issues in their 'friendly monster' ai, which seem to attempt to attack themselves for some reason when findradius() returns non-solid entities. Cvar_SetValueQuick (&sv_gameplayfix_blowupfallenzombies, 0); // hipnotic mission pack has issues with bobbing water entities 'jittering' between different heights on alternate frames at the default 0.0138889 ticrate, 0.02 avoids this issue Cvar_SetValueQuick (&sys_ticrate, 0.02); + // hipnotic mission pack has issues in their proximity mine sticking code, which causes them to bounce off. + Cvar_SetValueQuick (&sv_gameplayfix_slidemoveprojectiles, 0); } if (gamemode == GAME_ROGUE) { @@ -798,7 +832,7 @@ void SV_SendServerinfo (client_t *client) sb.data = (unsigned char *) buf; sb.maxsize = sizeof(buf); i = 0; - while(MakeDownloadPacket(sv.csqc_progname, sv.csqc_progdata, sv.csqc_progsize, sv.csqc_progcrc, i++, &sb, sv.protocol)) + while(MakeDownloadPacket(sv.csqc_progname, svs.csqc_progdata, sv.csqc_progsize, sv.csqc_progcrc, i++, &sb, sv.protocol)) SV_WriteDemoMessage(client, &sb, false); } @@ -1308,7 +1342,7 @@ void SV_MarkWriteEntityStateToClient(entity_state_t *s) ed = PRVM_EDICT_NUM(s->number); // if not touching a visible leaf - if (sv_cullentities_pvs.integer && sv.writeentitiestoclient_pvsbytes) + if (sv_cullentities_pvs.integer && !r_novis.integer && sv.writeentitiestoclient_pvsbytes) { if (ed->priv.server->pvs_numclusters < 0) { @@ -1411,6 +1445,7 @@ void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t * int i, numsendstates; entity_state_t *s; prvm_edict_t *camera; + qboolean success; // if there isn't enough space to accomplish anything, skip it if (msg->cursize + 25 > maxsize) @@ -1459,23 +1494,31 @@ void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t * else EntityFrameCSQC_WriteFrame(msg, maxsize, numsendstates, sv.writeentitiestoclient_sendstates, 0); + if(client->num_skippedentityframes >= 10) + need_empty = true; // force every 10th frame to be not empty (or cl_movement replay takes too long) + if (client->entitydatabase5) - EntityFrame5_WriteFrame(msg, maxsize, client->entitydatabase5, numsendstates, sv.writeentitiestoclient_sendstates, client - svs.clients + 1, client->movesequence, need_empty); + success = EntityFrame5_WriteFrame(msg, maxsize, client->entitydatabase5, numsendstates, sv.writeentitiestoclient_sendstates, client - svs.clients + 1, client->movesequence, need_empty); else if (client->entitydatabase4) { - EntityFrame4_WriteFrame(msg, maxsize, client->entitydatabase4, numsendstates, sv.writeentitiestoclient_sendstates); + success = EntityFrame4_WriteFrame(msg, maxsize, client->entitydatabase4, numsendstates, sv.writeentitiestoclient_sendstates); Protocol_WriteStatsReliable(); } else if (client->entitydatabase) { - EntityFrame_WriteFrame(msg, maxsize, client->entitydatabase, numsendstates, sv.writeentitiestoclient_sendstates, client - svs.clients + 1); + success = EntityFrame_WriteFrame(msg, maxsize, client->entitydatabase, numsendstates, sv.writeentitiestoclient_sendstates, client - svs.clients + 1); Protocol_WriteStatsReliable(); } else { - EntityFrameQuake_WriteFrame(msg, maxsize, numsendstates, sv.writeentitiestoclient_sendstates); + success = EntityFrameQuake_WriteFrame(msg, maxsize, numsendstates, sv.writeentitiestoclient_sendstates); Protocol_WriteStatsReliable(); } + + if(success) + client->num_skippedentityframes = 0; + else + ++client->num_skippedentityframes; } /* @@ -1642,6 +1685,15 @@ void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t statsf[STAT_MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION] = sv_airaccel_sideways_friction.value; statsf[STAT_MOVEVARS_FRICTION] = sv_friction.value; statsf[STAT_MOVEVARS_WATERFRICTION] = sv_waterfriction.value >= 0 ? sv_waterfriction.value : sv_friction.value; + statsf[STAT_MOVEVARS_AIRSTOPACCELERATE] = sv_airstopaccelerate.value; + statsf[STAT_MOVEVARS_AIRSTRAFEACCELERATE] = sv_airstrafeaccelerate.value; + statsf[STAT_MOVEVARS_MAXAIRSTRAFESPEED] = sv_maxairstrafespeed.value; + statsf[STAT_MOVEVARS_AIRCONTROL] = sv_aircontrol.value; + statsf[STAT_MOVEVARS_WARSOWBUNNY_AIRFORWARDACCEL] = sv_warsowbunny_airforwardaccel.value; + statsf[STAT_MOVEVARS_WARSOWBUNNY_ACCEL] = sv_warsowbunny_accel.value; + statsf[STAT_MOVEVARS_WARSOWBUNNY_TOPSPEED] = sv_warsowbunny_topspeed.value; + statsf[STAT_MOVEVARS_WARSOWBUNNY_TURNACCEL] = sv_warsowbunny_turnaccel.value; + statsf[STAT_MOVEVARS_WARSOWBUNNY_BACKTOSIDERATIO] = sv_warsowbunny_backtosideratio.value; statsf[STAT_FRAGLIMIT] = fraglimit.value; statsf[STAT_TIMELIMIT] = timelimit.value; @@ -2232,9 +2284,9 @@ static void SV_Download_f(void) Con_DPrintf("Downloading %s to %s\n", host_client->download_name, host_client->name); if(host_client->download_deflate) - host_client->download_file = FS_FileFromData(sv.csqc_progdata_deflated, sv.csqc_progsize_deflated, true); + host_client->download_file = FS_FileFromData(svs.csqc_progdata_deflated, svs.csqc_progsize_deflated, true); else - host_client->download_file = FS_FileFromData(sv.csqc_progdata, sv.csqc_progsize, true); + host_client->download_file = FS_FileFromData(svs.csqc_progdata, sv.csqc_progsize, true); // no, no space is needed between %s and %s :P Host_ClientCommands("\ncl_downloadbegin %i %s%s\n", (int)FS_FileSize(host_client->download_file), host_client->download_name, extensions); @@ -2397,7 +2449,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, false); + sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, s[0] == '*' ? sv.modelname : NULL); if (sv.state != ss_loading) { MSG_WriteByte(&sv.reliable_datagram, svc_precache); @@ -2636,37 +2688,37 @@ void SV_Prepare_CSQC(void) { fs_offset_t progsize; - if(sv.csqc_progdata) + if(svs.csqc_progdata) { Con_DPrintf("Unloading old CSQC data.\n"); - Mem_Free(sv.csqc_progdata); - if(sv.csqc_progdata_deflated) - Mem_Free(sv.csqc_progdata_deflated); + Mem_Free(svs.csqc_progdata); + if(svs.csqc_progdata_deflated) + Mem_Free(svs.csqc_progdata_deflated); } - sv.csqc_progdata = NULL; - sv.csqc_progdata_deflated = NULL; + svs.csqc_progdata = NULL; + svs.csqc_progdata_deflated = NULL; Con_Print("Loading csprogs.dat\n"); sv.csqc_progname[0] = 0; - sv.csqc_progdata = FS_LoadFile(csqc_progname.string, sv_mempool, false, &progsize); + svs.csqc_progdata = FS_LoadFile(csqc_progname.string, sv_mempool, false, &progsize); if(progsize > 0) { size_t deflated_size; sv.csqc_progsize = (int)progsize; - sv.csqc_progcrc = CRC_Block(sv.csqc_progdata, progsize); + sv.csqc_progcrc = CRC_Block(svs.csqc_progdata, progsize); strlcpy(sv.csqc_progname, csqc_progname.string, sizeof(sv.csqc_progname)); Con_Printf("server detected csqc progs file \"%s\" with size %i and crc %i\n", sv.csqc_progname, sv.csqc_progsize, sv.csqc_progcrc); Con_Print("Compressing csprogs.dat\n"); //unsigned char *FS_Deflate(const unsigned char *data, size_t size, size_t *deflated_size, int level, mempool_t *mempool); - sv.csqc_progdata_deflated = FS_Deflate(sv.csqc_progdata, progsize, &deflated_size, -1, sv_mempool); - sv.csqc_progsize_deflated = (int)deflated_size; + svs.csqc_progdata_deflated = FS_Deflate(svs.csqc_progdata, progsize, &deflated_size, -1, sv_mempool); + svs.csqc_progsize_deflated = (int)deflated_size; Con_Printf("Deflated: %g%%\n", 100.0 - 100.0 * (deflated_size / (float)progsize)); - Con_DPrintf("Uncompressed: %u\nCompressed: %u\n", (unsigned)sv.csqc_progsize, (unsigned)sv.csqc_progsize_deflated); + Con_DPrintf("Uncompressed: %u\nCompressed: %u\n", (unsigned)sv.csqc_progsize, (unsigned)svs.csqc_progsize_deflated); } } @@ -2699,7 +2751,7 @@ void SV_SaveSpawnparms (void) /* ================ -SV_/pawnServer +SV_SpawnServer This is called at the start of each level ================ @@ -2741,7 +2793,10 @@ void SV_SpawnServer (const char *server) SV_VM_End(); } - worldmodel = Mod_ForName(modelname, false, true, true); + // free q3 shaders so that any newly downloaded shaders will be active + Mod_FreeQ3Shaders(); + + worldmodel = Mod_ForName(modelname, false, true, NULL); if (!worldmodel || !worldmodel->TraceBox) { Con_Printf("Couldn't load map %s\n", modelname); @@ -2798,6 +2853,8 @@ void SV_SpawnServer (const char *server) // level's data which is no longer valiud cls.signon = 0; + Cvar_SetValue("halflifebsp", worldmodel->brush.ishlbsp); + if(*sv_random_seed.string) { srand(sv_random_seed.integer); @@ -2862,11 +2919,13 @@ void SV_SpawnServer (const char *server) strlcpy(sv.model_precache[0], "", sizeof(sv.model_precache[0])); strlcpy(sv.model_precache[1], sv.modelname, sizeof(sv.model_precache[1])); - for (i = 1;i < sv.worldmodel->brush.numsubmodels;i++) + 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, false); + sv.models[i+1] = Mod_ForName (sv.model_precache[i+1], false, false, sv.modelname); } + if(i < sv.worldmodel->brush.numsubmodels) + Con_Printf("Too many submodels (MAX_MODELS is %i)\n", MAX_MODELS); // // load the rest of the entities @@ -2920,22 +2979,26 @@ void SV_SpawnServer (const char *server) VectorClear(prog->edicts->fields.server->angles); // all setup is completed, any further precache statements are errors - sv.state = ss_active; +// sv.state = ss_active; // LordHavoc: workaround for svc_precache bug prog->allowworldwrites = false; // run two frames to allow everything to settle + prog->globals.server->time = sv.time = 1.0001; for (i = 0;i < 2;i++) { sv.frametime = 0.1; SV_Physics (); } - Mod_PurgeUnused(); + if (cls.state == ca_dedicated) + Mod_PurgeUnused(); // create a baseline for more efficient communications if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3) SV_CreateBaseline (); - + + sv.state = ss_active; // LordHavoc: workaround for svc_precache bug + // to prevent network timeouts realtime = Sys_DoubleTime();