]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - sv_main.c
Try to fix a dedicated server crash by moving the two csqc_ cvar initializations
[xonotic/darkplaces.git] / sv_main.c
index 92e123139e848909c7ae729d0fb97095af13b65a..0eaba842d06d120606ad102dad57aadb219884ee 100644 (file)
--- a/sv_main.c
+++ b/sv_main.c
@@ -20,6 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 // sv_main.c -- server main program
 
 #include "quakedef.h"
+#include "libcurl.h"
 
 void SV_VM_Init();
 void SV_VM_Setup();
@@ -43,15 +44,23 @@ static cvar_t sv_entpatch = {0, "sv_entpatch", "1", "enables loading of .ent fil
 
 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_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_stepdown = {0, "sv_gameplayfix_stepdown", "1", "attempts to step down stairs, not just up them (prevents the familiar thud..thud..thud.. when running down stairs and slopes)"};
+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)"};
 cvar_t sv_gameplayfix_stepwhilejumping = {0, "sv_gameplayfix_stepwhilejumping", "1", "applies step-up onto a ledge even while airborn, useful if you would otherwise just-miss the floor when running across small areas with gaps (for instance running across the moving platforms in dm2, or jumping to the megahealth and red armor in dm2 rather than using the bridge)"};
 cvar_t sv_gameplayfix_swiminbmodels = {0, "sv_gameplayfix_swiminbmodels", "1", "causes pointcontents (used to determine if you are in a liquid) to check bmodel entities as well as the world model, so you can swim around in (possibly moving) water bmodel entities"};
 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_blowupfallenzombies = {0, "sv_gameplayfix_blowupfallenzombies", "1", "causes findradius to detect SOLID_NOT entities such as zombies and corpses on the floor, allowing splash damage to apply to them"};
 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_qwplayerphysics = {0, "sv_gameplayfix_qwplayerphysics", "1", "changes water jumping to make it easier to get out of water, and prevents friction on landing when bunnyhopping"};
+cvar_t sv_gameplayfix_upwardvelocityclearsongroundflag = {0, "sv_gameplayfix_upwardvelocityclearsongroundflag", "1", "prevents monsters, items, and most other objects from being stuck to the floor when pushed around by damage, and other situations in mods"};
 
 cvar_t sv_progs = {0, "sv_progs", "progs.dat", "selects which quakec progs.dat file to run" };
 
+// TODO: move these cvars here
+extern cvar_t sv_clmovement_enable;
+extern cvar_t sv_clmovement_minping;
+extern cvar_t sv_clmovement_minping_disabletime;
+extern cvar_t sv_clmovement_waitforinput;
+
 server_t sv;
 server_static_t svs;
 
@@ -70,15 +79,29 @@ SV_Init
 */
 void SV_Init (void)
 {
+       // init the csqc progs cvars, since they are updated/used by the server code
+       // TODO: fix this since this is a quick hack to make some of [515]'s broken code run ;) [9/13/2006 Black]
+       extern cvar_t csqc_progname;
+       extern cvar_t csqc_progcrc;
+       Cvar_RegisterVariable (&csqc_progname);
+       Cvar_RegisterVariable (&csqc_progcrc);
+
        Cmd_AddCommand("sv_saveentfile", SV_SaveEntFile_f, "save map entities to .ent file (to allow external editing)");
        Cvar_RegisterVariable (&sv_maxvelocity);
        Cvar_RegisterVariable (&sv_gravity);
        Cvar_RegisterVariable (&sv_friction);
+       Cvar_RegisterVariable (&sv_waterfriction);
        Cvar_RegisterVariable (&sv_edgefriction);
        Cvar_RegisterVariable (&sv_stopspeed);
        Cvar_RegisterVariable (&sv_maxspeed);
        Cvar_RegisterVariable (&sv_maxairspeed);
        Cvar_RegisterVariable (&sv_accelerate);
+       Cvar_RegisterVariable (&sv_airaccelerate);
+       Cvar_RegisterVariable (&sv_wateraccelerate);
+       Cvar_RegisterVariable (&sv_clmovement_enable);
+       Cvar_RegisterVariable (&sv_clmovement_minping);
+       Cvar_RegisterVariable (&sv_clmovement_minping_disabletime);
+       Cvar_RegisterVariable (&sv_clmovement_waitforinput);
        Cvar_RegisterVariable (&sv_idealpitchscale);
        Cvar_RegisterVariable (&sv_aim);
        Cvar_RegisterVariable (&sv_nostep);
@@ -94,6 +117,8 @@ void SV_Init (void)
        Cvar_RegisterVariable (&sv_gameplayfix_setmodelrealbox);
        Cvar_RegisterVariable (&sv_gameplayfix_blowupfallenzombies);
        Cvar_RegisterVariable (&sv_gameplayfix_findradiusdistancetobox);
+       Cvar_RegisterVariable (&sv_gameplayfix_qwplayerphysics);
+       Cvar_RegisterVariable (&sv_gameplayfix_upwardvelocityclearsongroundflag);
        Cvar_RegisterVariable (&sv_protocolname);
        Cvar_RegisterVariable (&sv_ratelimitlocalplayer);
        Cvar_RegisterVariable (&sv_maxrate);
@@ -136,7 +161,7 @@ Make sure the event gets sent to all clients
 */
 void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count)
 {
-       int             i, v;
+       int i;
 
        if (sv.datagram.cursize > MAX_PACKETFRAGMENT-18)
                return;
@@ -145,14 +170,7 @@ void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count)
        MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
        MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
        for (i=0 ; i<3 ; i++)
-       {
-               v = dir[i]*16;
-               if (v > 127)
-                       v = 127;
-               else if (v < -128)
-                       v = -128;
-               MSG_WriteChar (&sv.datagram, v);
-       }
+               MSG_WriteChar (&sv.datagram, (int)bound(-128, dir[i]*16, 127));
        MSG_WriteByte (&sv.datagram, count);
        MSG_WriteByte (&sv.datagram, color);
 }
@@ -257,7 +275,7 @@ void SV_StartSound (prvm_edict_t *entity, int channel, const char *sample, int v
        if (field_mask & SND_VOLUME)
                MSG_WriteByte (&sv.datagram, volume);
        if (field_mask & SND_ATTENUATION)
-               MSG_WriteByte (&sv.datagram, attenuation*64);
+               MSG_WriteByte (&sv.datagram, (int)(attenuation*64));
        if (field_mask & SND_LARGEENTITY)
        {
                MSG_WriteShort (&sv.datagram, ent);
@@ -281,8 +299,8 @@ CLIENT SPAWNING
 ==============================================================================
 */
 
-static const char *SV_InitCmd; //[515]: svprogs able to send cmd to client on connect
-extern qboolean csqc_loaded;
+extern cvar_t csqc_progname;   //[515]: csqc crc check and right csprogs name according to progs.dat
+extern cvar_t csqc_progcrc;
 /*
 ================
 SV_SendServerinfo
@@ -327,16 +345,18 @@ void SV_SendServerinfo (client_t *client)
 
        SZ_Clear (&client->netconnection->message);
        MSG_WriteByte (&client->netconnection->message, svc_print);
-       dpsnprintf (message, sizeof (message), "\002\nServer: %s build %s (progs %i crc)", gamename, buildstring, prog->filecrc);
+       dpsnprintf (message, sizeof (message), "\nServer: %s build %s (progs %i crc)", gamename, buildstring, prog->filecrc);
        MSG_WriteString (&client->netconnection->message,message);
 
-       // FIXME: LordHavoc: this does not work on dedicated servers, needs fixing.
-//[515]: init csprogs according to version of svprogs, check the crc, etc.
-       if(csqc_loaded && (cls.state == ca_dedicated || PRVM_NUM_FOR_EDICT(client->edict) != 1))
+       //[515]: init csprogs according to version of svprogs, check the crc, etc.
+       if (FS_FileExists(csqc_progname.string))
        {
+               prvm_eval_t *val;
                MSG_WriteByte (&client->netconnection->message, svc_stufftext);
-               if(SV_InitCmd)
-                       MSG_WriteString (&client->netconnection->message, va("csqc_progcrc %i;%s\n", csqc_progcrc.integer, SV_InitCmd));
+               //[515]: init stufftext string (it is sent before svc_serverinfo)
+               val = PRVM_GETGLOBALFIELDVALUE(PRVM_ED_FindGlobalOffset("SV_InitCmd"));
+               if (val)
+                       MSG_WriteString (&client->netconnection->message, va("csqc_progcrc %i\n%s\n", csqc_progcrc.integer, PRVM_GetString(val->string)));
                else
                        MSG_WriteString (&client->netconnection->message, va("csqc_progcrc %i\n", csqc_progcrc.integer));
        }
@@ -362,8 +382,8 @@ void SV_SendServerinfo (client_t *client)
 
 // send music
        MSG_WriteByte (&client->netconnection->message, svc_cdtrack);
-       MSG_WriteByte (&client->netconnection->message, prog->edicts->fields.server->sounds);
-       MSG_WriteByte (&client->netconnection->message, prog->edicts->fields.server->sounds);
+       MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
+       MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
 
 // set view
        MSG_WriteByte (&client->netconnection->message, svc_setview);
@@ -372,6 +392,14 @@ void SV_SendServerinfo (client_t *client)
        MSG_WriteByte (&client->netconnection->message, svc_signonnum);
        MSG_WriteByte (&client->netconnection->message, 1);
 
+       {
+               client_t *save;
+               save = host_client;
+               host_client = client;
+               Curl_SendRequirements();
+               host_client = save;
+       }
+
        client->spawned = false;                // need prespawn, spawn, etc
 }
 
@@ -403,8 +431,8 @@ void SV_ConnectClient (int clientnum, netconn_t *netconnection)
 
        Con_DPrintf("Client %s connected\n", client->netconnection ? client->netconnection->address : "botclient");
 
-       strcpy(client->name, "unconnected");
-       strcpy(client->old_name, "unconnected");
+       strlcpy(client->name, "unconnected", sizeof(client->name));
+       strlcpy(client->old_name, "unconnected", sizeof(client->old_name));
        client->spawned = false;
        client->edict = PRVM_EDICT_NUM(clientnum+1);
        if (client->netconnection)
@@ -426,10 +454,10 @@ void SV_ConnectClient (int clientnum, netconn_t *netconnection)
                PRVM_ExecuteProgram (prog->globals.server->SetNewParms, "QC function SetNewParms is missing");
                for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
                        client->spawn_parms[i] = (&prog->globals.server->parm1)[i];
-       }
 
-       // set up the entity for this client (including .colormap, .team, etc)
-       PRVM_ED_ClearEdict(client->edict);
+               // set up the entity for this client (including .colormap, .team, etc)
+               PRVM_ED_ClearEdict(client->edict);
+       }
 
        // don't call SendServerinfo for a fresh botclient because its fields have
        // not been set up by the qc yet
@@ -526,9 +554,9 @@ qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *cs, int
                if (effects & 32)
                {
                        effects &= ~32;
-                       light[0] = 0.2;
-                       light[1] = 1;
-                       light[2] = 0.2;
+                       light[0] = (int)(0.2*256);
+                       light[1] = (int)(1.0*256);
+                       light[2] = (int)(0.2*256);
                        light[3] = 200;
                        lightpflags |= PFLAGS_FULLDYNAMIC;
                }
@@ -600,9 +628,9 @@ qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *cs, int
        val = PRVM_GETEDICTFIELDVALUE(ent, eval_colormod);
        if (val->vector[0] || val->vector[1] || val->vector[2])
        {
-               i = val->vector[0] * 32.0f;cs->colormod[0] = bound(0, i, 255);
-               i = val->vector[1] * 32.0f;cs->colormod[1] = bound(0, i, 255);
-               i = val->vector[2] * 32.0f;cs->colormod[2] = bound(0, i, 255);
+               i = (int)(val->vector[0] * 32.0f);cs->colormod[0] = bound(0, i, 255);
+               i = (int)(val->vector[1] * 32.0f);cs->colormod[1] = bound(0, i, 255);
+               i = (int)(val->vector[2] * 32.0f);cs->colormod[2] = bound(0, i, 255);
        }
 
        cs->modelindex = modelindex;
@@ -680,8 +708,9 @@ qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *cs, int
        }
        else
        {
-               VectorCopy(cs->origin, cullmins);
-               VectorCopy(cs->origin, cullmaxs);
+               // if there is no model (or it could not be loaded), use the physics box
+               VectorAdd(cs->origin, ent->fields.server->mins, cullmins);
+               VectorAdd(cs->origin, ent->fields.server->maxs, cullmaxs);
        }
        if (specialvisibilityradius)
        {
@@ -829,7 +858,7 @@ void SV_MarkWriteEntityStateToClient(entity_state_t *s)
                                testorigin[0] = (ed->priv.server->cullmins[0] + ed->priv.server->cullmaxs[0]) * 0.5f;
                                testorigin[1] = (ed->priv.server->cullmins[1] + ed->priv.server->cullmaxs[1]) * 0.5f;
                                testorigin[2] = (ed->priv.server->cullmins[2] + ed->priv.server->cullmaxs[2]) * 0.5f;
-                               sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, sv_writeentitiestoclient_testeye, testorigin, testorigin, SUPERCONTENTS_SOLID);
+                               sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
                                if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
                                        sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
                                else
@@ -838,7 +867,7 @@ void SV_MarkWriteEntityStateToClient(entity_state_t *s)
                                        testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]);
                                        testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]);
                                        testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]);
-                                       sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, sv_writeentitiestoclient_testeye, testorigin, testorigin, SUPERCONTENTS_SOLID);
+                                       sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
                                        if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
                                                sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
                                        else
@@ -849,7 +878,7 @@ void SV_MarkWriteEntityStateToClient(entity_state_t *s)
                                                        testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]);
                                                        testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]);
                                                        testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]);
-                                                       sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, sv_writeentitiestoclient_testeye, testorigin, testorigin, SUPERCONTENTS_SOLID);
+                                                       sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
                                                        if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
                                                                sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
                                                }
@@ -961,7 +990,7 @@ void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t
        int             items;
        prvm_eval_t     *val;
        vec3_t  punchvector;
-       unsigned char   viewzoom;
+       int             viewzoom;
        const char *s;
 
 //
@@ -971,8 +1000,8 @@ void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t
        {
                other = PRVM_PROG_TO_EDICT(ent->fields.server->dmg_inflictor);
                MSG_WriteByte (msg, svc_damage);
-               MSG_WriteByte (msg, ent->fields.server->dmg_save);
-               MSG_WriteByte (msg, ent->fields.server->dmg_take);
+               MSG_WriteByte (msg, (int)ent->fields.server->dmg_save);
+               MSG_WriteByte (msg, (int)ent->fields.server->dmg_take);
                for (i=0 ; i<3 ; i++)
                        MSG_WriteCoord (msg, other->fields.server->origin[i] + 0.5*(other->fields.server->mins[i] + other->fields.server->maxs[i]), sv.protocol);
 
@@ -1017,7 +1046,7 @@ void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t
 
        viewzoom = 255;
        if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_viewzoom)))
-               viewzoom = val->_float * 255.0f;
+               viewzoom = (int)(val->_float * 255.0f);
        if (viewzoom == 0)
                viewzoom = 255;
 
@@ -1042,18 +1071,18 @@ void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t
        }
 
        memset(stats, 0, sizeof(int[MAX_CL_STATS]));
-       stats[STAT_VIEWHEIGHT] = ent->fields.server->view_ofs[2];
+       stats[STAT_VIEWHEIGHT] = (int)ent->fields.server->view_ofs[2];
        stats[STAT_ITEMS] = items;
-       stats[STAT_WEAPONFRAME] = ent->fields.server->weaponframe;
-       stats[STAT_ARMOR] = ent->fields.server->armorvalue;
+       stats[STAT_WEAPONFRAME] = (int)ent->fields.server->weaponframe;
+       stats[STAT_ARMOR] = (int)ent->fields.server->armorvalue;
        stats[STAT_WEAPON] = client->weaponmodelindex;
-       stats[STAT_HEALTH] = ent->fields.server->health;
-       stats[STAT_AMMO] = ent->fields.server->currentammo;
-       stats[STAT_SHELLS] = ent->fields.server->ammo_shells;
-       stats[STAT_NAILS] = ent->fields.server->ammo_nails;
-       stats[STAT_ROCKETS] = ent->fields.server->ammo_rockets;
-       stats[STAT_CELLS] = ent->fields.server->ammo_cells;
-       stats[STAT_ACTIVEWEAPON] = ent->fields.server->weapon;
+       stats[STAT_HEALTH] = (int)ent->fields.server->health;
+       stats[STAT_AMMO] = (int)ent->fields.server->currentammo;
+       stats[STAT_SHELLS] = (int)ent->fields.server->ammo_shells;
+       stats[STAT_NAILS] = (int)ent->fields.server->ammo_nails;
+       stats[STAT_ROCKETS] = (int)ent->fields.server->ammo_rockets;
+       stats[STAT_CELLS] = (int)ent->fields.server->ammo_cells;
+       stats[STAT_ACTIVEWEAPON] = (int)ent->fields.server->weapon;
        stats[STAT_VIEWZOOM] = viewzoom;
        // the QC bumps these itself by sending svc_'s, so we have to keep them
        // zero or they'll be corrected by the engine
@@ -1092,14 +1121,14 @@ void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t
                MSG_WriteChar (msg, stats[STAT_VIEWHEIGHT]);
 
        if (bits & SU_IDEALPITCH)
-               MSG_WriteChar (msg, ent->fields.server->idealpitch);
+               MSG_WriteChar (msg, (int)ent->fields.server->idealpitch);
 
        for (i=0 ; i<3 ; i++)
        {
                if (bits & (SU_PUNCH1<<i))
                {
                        if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
-                               MSG_WriteChar(msg, ent->fields.server->punchangle[i]);
+                               MSG_WriteChar(msg, (int)ent->fields.server->punchangle[i]);
                        else
                                MSG_WriteAngle16i(msg, ent->fields.server->punchangle[i]);
                }
@@ -1113,7 +1142,7 @@ void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t
                if (bits & (SU_VELOCITY1<<i))
                {
                        if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
-                               MSG_WriteChar(msg, ent->fields.server->velocity[i] * (1.0f / 16.0f));
+                               MSG_WriteChar(msg, (int)(ent->fields.server->velocity[i] * (1.0f / 16.0f)));
                        else
                                MSG_WriteCoord32f(msg, ent->fields.server->velocity[i]);
                }
@@ -1138,7 +1167,7 @@ void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t
                MSG_WriteShort (msg, stats[STAT_CELLS]);
                MSG_WriteShort (msg, stats[STAT_ACTIVEWEAPON]);
                if (bits & SU_VIEWZOOM)
-                       MSG_WriteShort (msg, min(stats[STAT_VIEWZOOM], 65535));
+                       MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
        }
        else if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
        {
@@ -1166,9 +1195,9 @@ void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t
                if (bits & SU_VIEWZOOM)
                {
                        if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
-                               MSG_WriteByte (msg, min(stats[STAT_VIEWZOOM], 255));
+                               MSG_WriteByte (msg, bound(0, stats[STAT_VIEWZOOM], 255));
                        else
-                               MSG_WriteShort (msg, min(stats[STAT_VIEWZOOM], 65535));
+                               MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
                }
        }
 }
@@ -1246,7 +1275,7 @@ void SV_SendClientDatagram (client_t *client)
        }
 
 // send the datagram
-       NetConn_SendUnreliableMessage (client->netconnection, &msg);
+       NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol);
 }
 
 /*
@@ -1280,7 +1309,7 @@ void SV_UpdateToReliableMessages (void)
                {
                        if (host_client->spawned)
                                SV_BroadcastPrintf("%s changed name to %s\n", host_client->old_name, host_client->name);
-                       strcpy(host_client->old_name, host_client->name);
+                       strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
                        // send notification to all clients
                        MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
                        MSG_WriteByte (&sv.reliable_datagram, i);
@@ -1349,6 +1378,9 @@ void SV_SendClientMessages (void)
 {
        int i, prepared = false;
 
+       if (sv.protocol == PROTOCOL_QUAKEWORLD)
+               Sys_Error("SV_SendClientMessages: no quakeworld support\n");
+
 // update frags, names, etc
        SV_UpdateToReliableMessages();
 
@@ -1513,8 +1545,8 @@ void SV_CreateBaseline (void)
                // create entity baseline
                VectorCopy (svent->fields.server->origin, svent->priv.server->baseline.origin);
                VectorCopy (svent->fields.server->angles, svent->priv.server->baseline.angles);
-               svent->priv.server->baseline.frame = svent->fields.server->frame;
-               svent->priv.server->baseline.skin = svent->fields.server->skin;
+               svent->priv.server->baseline.frame = (int)svent->fields.server->frame;
+               svent->priv.server->baseline.skin = (int)svent->fields.server->skin;
                if (entnum > 0 && entnum <= svs.maxclients)
                {
                        svent->priv.server->baseline.colormap = entnum;
@@ -1523,7 +1555,7 @@ void SV_CreateBaseline (void)
                else
                {
                        svent->priv.server->baseline.colormap = 0;
-                       svent->priv.server->baseline.modelindex = svent->fields.server->modelindex;
+                       svent->priv.server->baseline.modelindex = (int)svent->fields.server->modelindex;
                }
 
                large = false;
@@ -1570,7 +1602,7 @@ void SV_SaveSpawnparms (void)
 {
        int             i, j;
 
-       svs.serverflags = prog->globals.server->serverflags;
+       svs.serverflags = (int)prog->globals.server->serverflags;
 
        for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
        {
@@ -1665,16 +1697,24 @@ void SV_SpawnServer (const char *server)
 
        svs.changelevel_issued = false;         // now safe to issue another
 
+       // make the map a required file for clients
+       Curl_ClearRequirements();
+       Curl_RequireFile(modelname);
+
 //
 // tell all connected clients that we are going to a new level
 //
        if (sv.active)
        {
-               // Tell all the clients that the server is changing levels
-               SV_VM_Begin();
-               MSG_WriteByte(&sv.reliable_datagram, svc_stufftext);
-               MSG_WriteString(&sv.reliable_datagram, "reconnect\n");
-               SV_VM_End();
+               client_t *client;
+               for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
+               {
+                       if (client->netconnection)
+                       {
+                               MSG_WriteByte(&client->netconnection->message, svc_stufftext);
+                               MSG_WriteString(&client->netconnection->message, "reconnect\n");
+                       }
+               }
        }
        else
        {
@@ -1695,9 +1735,10 @@ void SV_SpawnServer (const char *server)
 //
 // set up the new server
 //
-       Host_ClearMemory ();
-
        memset (&sv, 0, sizeof(sv));
+       // if running a local client, make sure it doesn't try to access the last
+       // level's data which is no longer valiud
+       cls.signon = 0;
 
        SV_VM_Setup();
 
@@ -1768,7 +1809,7 @@ void SV_SpawnServer (const char *server)
        worldmodel->used = true;
 
        strlcpy (sv.name, server, sizeof (sv.name));
-       strcpy(sv.modelname, modelname);
+       strlcpy(sv.modelname, modelname, sizeof(sv.modelname));
        sv.worldmodel = worldmodel;
        sv.models[1] = sv.worldmodel;
 
@@ -1821,10 +1862,7 @@ void SV_SpawnServer (const char *server)
        }
 
        // load replacement entity file if found
-       entities = NULL;
-       if (sv_entpatch.integer)
-               entities = (char *)FS_LoadFile(va("maps/%s.ent", sv.name), tempmempool, true, NULL);
-       if (entities)
+       if (sv_entpatch.integer && (entities = (char *)FS_LoadFile(va("maps/%s.ent", sv.name), tempmempool, true, NULL)))
        {
                Con_Printf("Loaded maps/%s.ent\n", sv.name);
                PRVM_ED_LoadFromFile (entities);
@@ -1844,7 +1882,7 @@ void SV_SpawnServer (const char *server)
 // run two frames to allow everything to settle
        for (i = 0;i < 2;i++)
        {
-               sv.frametime = host_frametime = 0.1;
+               sv.frametime = 0.1;
                SV_Physics ();
        }
 
@@ -2152,14 +2190,18 @@ int eval_playerskin;
 int eval_SendEntity;
 int eval_Version;
 int eval_customizeentityforclient;
+int eval_dphitcontentsmask;
+
+int gval_trace_dpstartcontents;
+int gval_trace_dphitcontents;
+int gval_trace_dphitq3surfaceflags;
+int gval_trace_dphittexturename;
 
 mfunction_t *SV_PlayerPhysicsQC;
 mfunction_t *EndFrameQC;
 //KrimZon - SERVER COMMANDS IN QUAKEC
 mfunction_t *SV_ParseClientCommandQC;
 
-ddef_t *PRVM_ED_FindGlobal(const char *name);
-
 void SV_VM_FindEdictFieldOffsets(void)
 {
        eval_gravity = PRVM_ED_FindFieldOffset("gravity");
@@ -2224,6 +2266,7 @@ void SV_VM_FindEdictFieldOffsets(void)
        eval_SendEntity = PRVM_ED_FindFieldOffset("SendEntity");
        eval_Version = PRVM_ED_FindFieldOffset("Version");
        eval_customizeentityforclient = PRVM_ED_FindFieldOffset("customizeentityforclient");
+       eval_dphitcontentsmask = PRVM_ED_FindFieldOffset("dphitcontentsmask");
 
        // LordHavoc: allowing QuakeC to override the player movement code
        SV_PlayerPhysicsQC = PRVM_ED_FindFunction ("SV_PlayerPhysics");
@@ -2231,12 +2274,10 @@ void SV_VM_FindEdictFieldOffsets(void)
        EndFrameQC = PRVM_ED_FindFunction ("EndFrame");
        //KrimZon - SERVER COMMANDS IN QUAKEC
        SV_ParseClientCommandQC = PRVM_ED_FindFunction ("SV_ParseClientCommand");
-
-       //[515]: init stufftext string (it is sent before svc_serverinfo)
-       if(PRVM_ED_FindGlobal("SV_InitCmd") && PRVM_ED_FindGlobal("SV_InitCmd")->type & ev_string)
-               SV_InitCmd = PRVM_G_STRING(PRVM_ED_FindGlobal("SV_InitCmd")->ofs);
-       else
-               SV_InitCmd = NULL;
+       gval_trace_dpstartcontents = PRVM_ED_FindGlobalOffset("trace_dpstartcontents");
+       gval_trace_dphitcontents = PRVM_ED_FindGlobalOffset("trace_dphitcontents");
+       gval_trace_dphitq3surfaceflags = PRVM_ED_FindGlobalOffset("trace_dphitq3surfaceflags");
+       gval_trace_dphittexturename = PRVM_ED_FindGlobalOffset("trace_dphittexturename");
 }
 
 #define REQFIELDS (sizeof(reqfields) / sizeof(prvm_required_field_t))
@@ -2309,10 +2350,14 @@ prvm_required_field_t reqfields[] =
 
 void SV_VM_Setup(void)
 {
+       unsigned char *csprogsdata;
+       fs_offset_t csprogsdatasize;
+       unsigned int csprogsdatacrc;
        PRVM_Begin;
        PRVM_InitProg( PRVM_SERVERPROG );
 
        // allocate the mempools
+       // TODO: move the magic numbers/constants into #defines [9/13/2006 Black]
        prog->progs_mempool = Mem_AllocPool("Server Progs", 0, NULL);
        prog->builtins = vm_sv_builtins;
        prog->numbuiltins = vm_sv_numbuiltins;
@@ -2343,6 +2388,16 @@ void SV_VM_Setup(void)
        EntityFrameCSQC_ClearVersions();//[515]: csqc
 
        PRVM_End;
+
+       // see if there is a csprogs.dat installed, and if so, set the csqc_progcrc accordingly, this will be sent to connecting clients to tell them to only load a matching csprogs.dat file
+       csprogsdatacrc = 0;
+       csprogsdata = FS_LoadFile(csqc_progname.string, tempmempool, true, &csprogsdatasize);
+       if (csprogsdata)
+       {
+               csprogsdatacrc = CRC_Block(csprogsdata, csprogsdatasize);
+               Mem_Free(csprogsdata);
+       }
+       Cvar_SetValueQuick(&csqc_progcrc, csprogsdatacrc);
 }
 
 void SV_VM_Begin(void)