// sv_main.c -- server main program
#include "quakedef.h"
+#include "libcurl.h"
void SV_VM_Init();
void SV_VM_Setup();
cvar_t sv_protocolname = {0, "sv_protocolname", "DP7", "selects network protocol to host for (values include QUAKE, QUAKEDP, NEHAHRAMOVIE, DP1 and up)"};
cvar_t sv_ratelimitlocalplayer = {0, "sv_ratelimitlocalplayer", "0", "whether to apply rate limiting to the local player in a listen server (only useful for testing)"};
cvar_t sv_maxrate = {CVAR_SAVE | CVAR_NOTIFY, "sv_maxrate", "10000", "upper limit on client rate cvar, should reflect your network connection quality"};
+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_inarchive = {0, "sv_allowdownloads_inarchive", "0", "whether to allow downloads from archives (pak/pk3)"};
+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)"};
+cvar_t sv_allowdownloads_dlcache = {0, "sv_allowdownloads_dlcache", "0", "whether to allow downloads of dlcache files (dlcache/)"};
+
+extern cvar_t sv_random_seed;
static cvar_t sv_cullentities_pvs = {0, "sv_cullentities_pvs", "1", "fast but loose culling of hidden entities"}; // fast but loose
static cvar_t sv_cullentities_trace = {0, "sv_cullentities_trace", "0", "somewhat slow but very tight culling of hidden entities, minimizes network traffic and makes wallhack cheats useless"}; // tends to get false negatives, uses a timeout to keep entities visible a short time after becoming hidden
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_gameplayfix_droptofloorstartsolid = {0, "sv_gameplayfix_droptofloorstartsolid", "1", "prevents items and monsters that start in a solid area from falling out of the level (makes droptofloor treat trace_startsolid as an acceptable outcome)"};
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;
//============================================================================
extern void SV_Phys_Init (void);
-extern void SV_World_Init (void);
static void SV_SaveEntFile_f(void);
+static void SV_StartDownload_f(void);
+static void SV_Download_f(void);
+
+void SV_AreaStats_f(void)
+{
+ World_PrintAreaStats(&sv.world, "server");
+}
/*
===============
*/
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; //[515]: csqc crc check and right csprogs name according to progs.dat
+ extern cvar_t csqc_progcrc;
+ extern cvar_t csqc_progsize;
+ Cvar_RegisterVariable (&csqc_progname);
+ Cvar_RegisterVariable (&csqc_progcrc);
+ Cvar_RegisterVariable (&csqc_progsize);
+
Cmd_AddCommand("sv_saveentfile", SV_SaveEntFile_f, "save map entities to .ent file (to allow external editing)");
+ Cmd_AddCommand("sv_areastats", SV_AreaStats_f, "prints statistics on entity culling during collision traces");
+ Cmd_AddCommand_WithClientCommand("sv_startdownload", NULL, SV_StartDownload_f, "begins sending a file to the client (network protocol use only)");
+ Cmd_AddCommand_WithClientCommand("download", NULL, SV_Download_f, "downloads a specified file from the server");
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);
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_gameplayfix_droptofloorstartsolid);
Cvar_RegisterVariable (&sv_protocolname);
Cvar_RegisterVariable (&sv_ratelimitlocalplayer);
Cvar_RegisterVariable (&sv_maxrate);
+ Cvar_RegisterVariable (&sv_allowdownloads);
+ Cvar_RegisterVariable (&sv_allowdownloads_inarchive);
+ Cvar_RegisterVariable (&sv_allowdownloads_archive);
+ Cvar_RegisterVariable (&sv_allowdownloads_config);
+ Cvar_RegisterVariable (&sv_allowdownloads_dlcache);
Cvar_RegisterVariable (&sv_progs);
SV_VM_Init();
SV_Phys_Init();
- SV_World_Init();
sv_mempool = Mem_AllocPool("server", 0, NULL);
}
*/
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;
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);
}
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);
==============================================================================
*/
-static const char *SV_InitCmd; //[515]: svprogs able to send cmd to client on connect
-extern qboolean csqc_loaded;
/*
================
SV_SendServerinfo
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 (sv.csqc_progname[0])
{
+ prvm_eval_t *val;
+ Con_DPrintf("sending csqc info to client (\"%s\" with size %i and crc %i)\n", sv.csqc_progname, sv.csqc_progsize, sv.csqc_progcrc);
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));
- else
- MSG_WriteString (&client->netconnection->message, va("csqc_progcrc %i\n", csqc_progcrc.integer));
+ MSG_WriteString (&client->netconnection->message, va("csqc_progname %s\n", sv.csqc_progname));
+ MSG_WriteByte (&client->netconnection->message, svc_stufftext);
+ MSG_WriteString (&client->netconnection->message, va("csqc_progsize %i\n", sv.csqc_progsize));
+ MSG_WriteByte (&client->netconnection->message, svc_stufftext);
+ MSG_WriteString (&client->netconnection->message, va("csqc_progcrc %i\n", sv.csqc_progcrc));
+ //[515]: init stufftext string (it is sent before svc_serverinfo)
+ val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.SV_InitCmd);
+ if (val)
+ {
+ MSG_WriteByte (&client->netconnection->message, svc_stufftext);
+ MSG_WriteString (&client->netconnection->message, va("%s\n", PRVM_GetString(val->string)));
+ }
+ }
+
+ if (sv_allowdownloads.integer)
+ {
+ MSG_WriteByte (&client->netconnection->message, svc_stufftext);
+ MSG_WriteString (&client->netconnection->message, "cl_serverextension_download 1");
}
MSG_WriteByte (&client->netconnection->message, svc_serverinfo);
// 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);
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
}
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)
modelindex = (i >= 1 && i < MAX_MODELS && *PRVM_GetString(ent->fields.server->model)) ? i : 0;
flags = 0;
- i = (int)(PRVM_GETEDICTFIELDVALUE(ent, eval_glow_size)->_float * 0.25f);
+ i = (int)(PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.glow_size)->_float * 0.25f);
glowsize = (unsigned char)bound(0, i, 255);
- if (PRVM_GETEDICTFIELDVALUE(ent, eval_glow_trail)->_float)
+ if (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.glow_trail)->_float)
flags |= RENDER_GLOWTRAIL;
- f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[0]*256;
+ f = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.color)->vector[0]*256;
light[0] = (unsigned short)bound(0, f, 65535);
- f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[1]*256;
+ f = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.color)->vector[1]*256;
light[1] = (unsigned short)bound(0, f, 65535);
- f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[2]*256;
+ f = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.color)->vector[2]*256;
light[2] = (unsigned short)bound(0, f, 65535);
- f = PRVM_GETEDICTFIELDVALUE(ent, eval_light_lev)->_float;
+ f = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.light_lev)->_float;
light[3] = (unsigned short)bound(0, f, 65535);
- lightstyle = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_style)->_float;
- lightpflags = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_pflags)->_float;
+ lightstyle = (unsigned char)PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.style)->_float;
+ lightpflags = (unsigned char)PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.pflags)->_float;
if (gamemode == GAME_TENEBRAE)
{
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;
}
// early culling checks
// (final culling is done by SV_MarkWriteEntityStateToClient)
- customizeentityforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_customizeentityforclient)->function;
+ customizeentityforclient = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.customizeentityforclient)->function;
if (!customizeentityforclient)
{
if (e > svs.maxclients && (!modelindex && !specialvisibilityradius))
cs->modelindex = modelindex;
cs->skin = (unsigned)ent->fields.server->skin;
cs->frame = (unsigned)ent->fields.server->frame;
- cs->viewmodelforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)->edict;
- cs->exteriormodelforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_exteriormodeltoclient)->edict;
- cs->nodrawtoclient = PRVM_GETEDICTFIELDVALUE(ent, eval_nodrawtoclient)->edict;
- cs->drawonlytoclient = PRVM_GETEDICTFIELDVALUE(ent, eval_drawonlytoclient)->edict;
+ cs->viewmodelforclient = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.viewmodelforclient)->edict;
+ cs->exteriormodelforclient = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.exteriormodeltoclient)->edict;
+ cs->nodrawtoclient = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.nodrawtoclient)->edict;
+ cs->drawonlytoclient = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.drawonlytoclient)->edict;
cs->customizeentityforclient = customizeentityforclient;
- cs->tagentity = PRVM_GETEDICTFIELDVALUE(ent, eval_tag_entity)->edict;
- cs->tagindex = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_tag_index)->_float;
+ cs->tagentity = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)->edict;
+ cs->tagindex = (unsigned char)PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_index)->_float;
cs->glowsize = glowsize;
// don't need to init cs->colormod because the defaultstate did that for us
//cs->colormod[0] = cs->colormod[1] = cs->colormod[2] = 32;
- val = PRVM_GETEDICTFIELDVALUE(ent, eval_colormod);
+ val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.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;
cs->alpha = 255;
- f = (PRVM_GETEDICTFIELDVALUE(ent, eval_alpha)->_float * 255.0f);
+ f = (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.alpha)->_float * 255.0f);
if (f)
{
i = (int)f;
cs->alpha = (unsigned char)bound(0, i, 255);
}
// halflife
- f = (PRVM_GETEDICTFIELDVALUE(ent, eval_renderamt)->_float);
+ f = (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderamt)->_float);
if (f)
{
i = (int)f;
}
cs->scale = 16;
- f = (PRVM_GETEDICTFIELDVALUE(ent, eval_scale)->_float * 16.0f);
+ f = (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale)->_float * 16.0f);
if (f)
{
i = (int)f;
}
cs->glowcolor = 254;
- f = (PRVM_GETEDICTFIELDVALUE(ent, eval_glow_color)->_float);
+ f = (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.glow_color)->_float);
if (f)
cs->glowcolor = (int)f;
- if (PRVM_GETEDICTFIELDVALUE(ent, eval_fullbright)->_float)
+ if (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.fullbright)->_float)
cs->effects |= EF_FULLBRIGHT;
if (ent->fields.server->movetype == MOVETYPE_STEP)
}
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)
{
int items;
prvm_eval_t *val;
vec3_t punchvector;
- unsigned char viewzoom;
+ int viewzoom;
const char *s;
//
{
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);
// stuff the sigil bits into the high bits of items for sbar, or else
// mix in items2
- val = PRVM_GETEDICTFIELDVALUE(ent, eval_items2);
+ val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.items2);
if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
items = (int)ent->fields.server->items | ((int)val->_float << 23);
else
items = (int)ent->fields.server->items | ((int)prog->globals.server->serverflags << 28);
VectorClear(punchvector);
- if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_punchvector)))
+ if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.punchvector)))
VectorCopy(val->vector, punchvector);
// cache weapon model name and index in client struct to save time
}
viewzoom = 255;
- if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_viewzoom)))
- viewzoom = val->_float * 255.0f;
+ if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.viewzoom)))
+ viewzoom = (int)(val->_float * 255.0f);
if (viewzoom == 0)
viewzoom = 255;
}
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;
+ stats[STAT_TOTALSECRETS] = prog->globals.server->total_secrets;
+ stats[STAT_TOTALMONSTERS] = prog->globals.server->total_monsters;
// the QC bumps these itself by sending svc_'s, so we have to keep them
// zero or they'll be corrected by the engine
- //stats[STAT_TOTALSECRETS] = prog->globals.server->total_secrets;
- //stats[STAT_TOTALMONSTERS] = prog->globals.server->total_monsters;
//stats[STAT_SECRETS] = prog->globals.server->found_secrets;
//stats[STAT_MONSTERS] = prog->globals.server->killed_monsters;
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]);
}
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]);
}
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)
{
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));
}
}
}
static unsigned char sv_sendclientdatagram_buf[NET_MAXMESSAGE]; // FIXME?
void SV_SendClientDatagram (client_t *client)
{
- int rate, maxrate, maxsize, maxsize2;
+ int rate, maxrate, maxsize, maxsize2, downloadsize;
sizebuf_t msg;
int stats[MAX_CL_STATS];
else
{
// PROTOCOL_DARKPLACES5 and later support packet size limiting of updates
- maxrate = bound(NET_MINRATE, sv_maxrate.integer, NET_MAXRATE);
+ maxrate = max(NET_MINRATE, sv_maxrate.integer);
if (sv_maxrate.integer != maxrate)
Cvar_SetValueQuick(&sv_maxrate, maxrate);
// this rate limiting does not understand sys_ticrate 0
// (but no one should be running that on a server!)
rate = bound(NET_MINRATE, client->rate, maxrate);
- rate = (int)(client->rate * sys_ticrate.value);
- maxsize = bound(100, rate, 1400);
+ rate = (int)(rate * sys_ticrate.value);
+ maxsize = bound(50, rate, 1400);
maxsize2 = 1400;
}
+ // while downloading, limit entity updates to half the packet
+ // (any leftover space will be used for downloading)
+ if (host_client->download_file)
+ maxsize /= 2;
+
msg.data = sv_sendclientdatagram_buf;
msg.maxsize = maxsize;
msg.cursize = 0;
{
// the player isn't totally in the game yet
// send small keepalive messages if too much time has passed
+ msg.maxsize = maxsize2;
client->keepalivetime = realtime + 5;
MSG_WriteChar (&msg, svc_nop);
}
+ msg.maxsize = maxsize2;
+
+ // if a download is active, see if there is room to fit some download data
+ // in this packet
+ downloadsize = maxsize * 2 - msg.cursize - 7;
+ if (host_client->download_file && host_client->download_started && downloadsize > 0)
+ {
+ fs_offset_t downloadstart;
+ unsigned char data[1400];
+ downloadstart = FS_Tell(host_client->download_file);
+ downloadsize = min(downloadsize, (int)sizeof(data));
+ downloadsize = FS_Read(host_client->download_file, data, downloadsize);
+ // note this sends empty messages if at the end of the file, which is
+ // necessary to keep the packet loss logic working
+ // (the last blocks may be lost and need to be re-sent, and that will
+ // only occur if the client acks the empty end messages, revealing
+ // a gap in the download progress, causing the last blocks to be
+ // sent again)
+ MSG_WriteChar (&msg, svc_downloaddata);
+ MSG_WriteLong (&msg, downloadstart);
+ MSG_WriteShort (&msg, downloadsize);
+ if (downloadsize > 0)
+ SZ_Write (&msg, data, downloadsize);
+ }
+
// send the datagram
NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol);
}
{
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);
// DP_SV_CLIENTCOLORS
// this is always found (since it's added by the progs loader)
- if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_clientcolors)))
+ if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.clientcolors)))
host_client->colors = (int)val->_float;
if (host_client->old_colors != host_client->colors)
{
}
// NEXUIZ_PLAYERMODEL
- if( eval_playermodel ) {
- model = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string);
+ if( prog->fieldoffsets.playermodel >= 0 ) {
+ model = PRVM_GetString(PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string);
if (model == NULL)
model = "";
// always point the string back at host_client->name to keep it safe
strlcpy (host_client->playermodel, model, sizeof (host_client->playermodel));
- PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
+ PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
}
// NEXUIZ_PLAYERSKIN
- if( eval_playerskin ) {
- skin = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string);
+ if( prog->fieldoffsets.playerskin >= 0 ) {
+ skin = PRVM_GetString(PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string);
if (skin == NULL)
skin = "";
// always point the string back at host_client->name to keep it safe
strlcpy (host_client->playerskin, skin, sizeof (host_client->playerskin));
- PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
+ PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
}
// frags
SV_CleanupEnts();
}
+void SV_StartDownload_f(void)
+{
+ if (host_client->download_file)
+ host_client->download_started = true;
+}
+
+void SV_Download_f(void)
+{
+ const char *whichpack, *whichpack2, *extension;
+
+ if (Cmd_Argc() != 2)
+ {
+ SV_ClientPrintf("usage: download <filename>\n");
+ return;
+ }
+
+ if (FS_CheckNastyPath(Cmd_Argv(1), false))
+ {
+ SV_ClientPrintf("Download rejected: nasty filename \"%s\"\n", Cmd_Argv(1));
+ return;
+ }
+
+ if (host_client->download_file)
+ {
+ // at this point we'll assume the previous download should be aborted
+ Con_DPrintf("Download of %s aborted by %s starting a new download\n", host_client->download_name, host_client->name);
+ Host_ClientCommands("\nstopdownload\n");
+
+ // close the file and reset variables
+ FS_Close(host_client->download_file);
+ host_client->download_file = NULL;
+ host_client->download_name[0] = 0;
+ host_client->download_expectedposition = 0;
+ host_client->download_started = false;
+ }
+
+ if (!sv_allowdownloads.integer)
+ {
+ SV_ClientPrintf("Downloads are disabled on this server\n");
+ Host_ClientCommands("\nstopdownload\n");
+ return;
+ }
+
+ strlcpy(host_client->download_name, Cmd_Argv(1), sizeof(host_client->download_name));
+ extension = FS_FileExtension(host_client->download_name);
+
+ // host_client is asking to download a specified file
+ if (developer.integer >= 100)
+ Con_Printf("Download request for %s by %s\n", host_client->download_name, host_client->name);
+
+ if (!FS_FileExists(host_client->download_name))
+ {
+ SV_ClientPrintf("Download rejected: server does not have the file \"%s\"\nYou may need to separately download or purchase the data archives for this game/mod to get this file\n", host_client->download_name);
+ Host_ClientCommands("\nstopdownload\n");
+ return;
+ }
+
+ // check if the user is trying to download part of registered Quake(r)
+ whichpack = FS_WhichPack(host_client->download_name);
+ whichpack2 = FS_WhichPack("gfx/pop.lmp");
+ if ((whichpack && whichpack2 && !strcasecmp(whichpack, whichpack2)) || FS_IsRegisteredQuakePack(host_client->download_name))
+ {
+ SV_ClientPrintf("Download rejected: file \"%s\" is part of registered Quake(r)\nYou must purchase Quake(r) from id Software or a retailer to get this file\nPlease go to http://www.idsoftware.com/games/quake/quake/index.php?game_section=buy\n", host_client->download_name);
+ Host_ClientCommands("\nstopdownload\n");
+ return;
+ }
+
+ // check if the server has forbidden archive downloads entirely
+ if (!sv_allowdownloads_inarchive.integer)
+ {
+ whichpack = FS_WhichPack(host_client->download_name);
+ if (whichpack)
+ {
+ SV_ClientPrintf("Download rejected: file \"%s\" is in an archive (\"%s\")\nYou must separately download or purchase the data archives for this game/mod to get this file\n", host_client->download_name, whichpack);
+ Host_ClientCommands("\nstopdownload\n");
+ return;
+ }
+ }
+
+ if (!sv_allowdownloads_config.integer)
+ {
+ if (!strcasecmp(extension, "cfg"))
+ {
+ SV_ClientPrintf("Download rejected: file \"%s\" is a .cfg file which is forbidden for security reasons\nYou must separately download or purchase the data archives for this game/mod to get this file\n", host_client->download_name);
+ Host_ClientCommands("\nstopdownload\n");
+ return;
+ }
+ }
+
+ if (!sv_allowdownloads_dlcache.integer)
+ {
+ if (!strncasecmp(host_client->download_name, "dlcache/", 8))
+ {
+ SV_ClientPrintf("Download rejected: file \"%s\" is in the dlcache/ directory which is forbidden for security reasons\nYou must separately download or purchase the data archives for this game/mod to get this file\n", host_client->download_name);
+ Host_ClientCommands("\nstopdownload\n");
+ return;
+ }
+ }
+
+ if (!sv_allowdownloads_archive.integer)
+ {
+ if (!strcasecmp(extension, "pak") || !strcasecmp(extension, "pk3"))
+ {
+ SV_ClientPrintf("Download rejected: file \"%s\" is an archive\nYou must separately download or purchase the data archives for this game/mod to get this file\n", host_client->download_name);
+ Host_ClientCommands("\nstopdownload\n");
+ return;
+ }
+ }
+
+ host_client->download_file = FS_Open(host_client->download_name, "rb", true, false);
+ if (!host_client->download_file)
+ {
+ SV_ClientPrintf("Download rejected: server could not open the file \"%s\"\n", host_client->download_name);
+ Host_ClientCommands("\nstopdownload\n");
+ return;
+ }
+
+ if (FS_FileSize(host_client->download_file) > 1<<30)
+ {
+ SV_ClientPrintf("Download rejected: file \"%s\" is very large\n", host_client->download_name);
+ Host_ClientCommands("\nstopdownload\n");
+ FS_Close(host_client->download_file);
+ host_client->download_file = NULL;
+ return;
+ }
+
+ Con_DPrintf("Downloading %s to %s\n", host_client->download_name, host_client->name);
+
+ Host_ClientCommands("\ncl_downloadbegin %i %s\n", (int)FS_FileSize(host_client->download_file), host_client->download_name);
+
+ host_client->download_expectedposition = 0;
+ host_client->download_started = false;
+
+ // the rest of the download process is handled in SV_SendClientDatagram
+ // and other code dealing with svc_downloaddata and clc_ackdownloaddata
+ //
+ // no svc_downloaddata messages will be sent until sv_startdownload is
+ // sent by the client
+}
/*
==============================================================================
// 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;
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;
{
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++)
{
SV_UnlinkEdict(prog->edicts + i);
memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
}
- SV_ClearWorld();
+ World_Clear(&sv.world);
prog->max_edicts = min(prog->max_edicts + 256, MAX_EDICTS);
prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
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
//
// level's data which is no longer valiud
cls.signon = 0;
+ if(*sv_random_seed.string)
+ {
+ srand(sv_random_seed.integer);
+ Con_Printf("NOTE: random seed is %d; use for debugging/benchmarking only!\nUnset sv_random_seed to get real random numbers again.\n", sv_random_seed.integer);
+ }
+
SV_VM_Setup();
sv.active = true;
prog->allowworldwrites = true;
sv.paused = false;
- *prog->time = sv.time = 1.0;
+ prog->globals.server->time = sv.time = 1.0;
Mod_ClearUsed();
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;
//
// clear world interaction links
//
- SV_ClearWorld ();
+ VectorCopy(sv.worldmodel->normalmins, sv.world.areagrid_mins);
+ VectorCopy(sv.worldmodel->normalmaxs, sv.world.areagrid_maxs);
+ World_Clear(&sv.world);
strlcpy(sv.sound_precache[0], "", sizeof(sv.sound_precache[0]));
ent->fields.server->modelindex = 1; // world model
ent->fields.server->solid = SOLID_BSP;
ent->fields.server->movetype = MOVETYPE_PUSH;
+ VectorCopy(sv.worldmodel->normalmins, ent->fields.server->mins);
+ VectorCopy(sv.worldmodel->normalmaxs, ent->fields.server->maxs);
+ VectorCopy(sv.worldmodel->normalmins, ent->fields.server->absmin);
+ VectorCopy(sv.worldmodel->normalmaxs, ent->fields.server->absmax);
if (coop.value)
prog->globals.server->coop = coop.integer;
// 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 ();
}
for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
{
if (!ent->priv.server->free)
- SV_UnlinkEdict(prog->edicts + i);
+ World_UnlinkEdict(prog->edicts + i);
memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
}
- SV_ClearWorld();
+ World_Clear(&sv.world);
}
void SV_VM_CB_EndIncreaseEdicts(void)
int i;
prvm_edict_t *ent;
- for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
- {
- // link every entity except world
+ // link every entity except world
+ for (i = 1, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
if (!ent->priv.server->free)
SV_LinkEdict(ent, false);
- }
}
void SV_VM_CB_InitEdict(prvm_edict_t *e)
// DP_SV_CLIENTNAME and DP_SV_CLIENTCOLORS will not immediately
// reset them
e->fields.server->netname = PRVM_SetEngineString(svs.clients[num].name);
- if ((val = PRVM_GETEDICTFIELDVALUE(e, eval_clientcolors)))
+ if ((val = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.clientcolors)))
val->_float = svs.clients[num].colors;
// NEXUIZ_PLAYERMODEL and NEXUIZ_PLAYERSKIN
- if( eval_playermodel )
- PRVM_GETEDICTFIELDVALUE(e, eval_playermodel)->string = PRVM_SetEngineString(svs.clients[num].playermodel);
- if( eval_playerskin )
- PRVM_GETEDICTFIELDVALUE(e, eval_playerskin)->string = PRVM_SetEngineString(svs.clients[num].playerskin);
+ if( prog->fieldoffsets.playermodel >= 0 )
+ PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(svs.clients[num].playermodel);
+ if( prog->fieldoffsets.playerskin >= 0 )
+ PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(svs.clients[num].playerskin);
}
}
void SV_VM_CB_FreeEdict(prvm_edict_t *ed)
{
- SV_UnlinkEdict (ed); // unlink from world bsp
+ World_UnlinkEdict(ed); // unlink from world bsp
ed->fields.server->model = 0;
ed->fields.server->takedamage = 0;
Cvar_RegisterVariable (&cutscene); // for Nehahra but useful to other mods as well
}
-// LordHavoc: in an effort to eliminate time wasted on GetEdictFieldValue... these are defined as externs in progs.h
-int eval_gravity;
-int eval_button3;
-int eval_button4;
-int eval_button5;
-int eval_button6;
-int eval_button7;
-int eval_button8;
-int eval_button9;
-int eval_button10;
-int eval_button11;
-int eval_button12;
-int eval_button13;
-int eval_button14;
-int eval_button15;
-int eval_button16;
-int eval_buttonuse;
-int eval_buttonchat;
-int eval_glow_size;
-int eval_glow_trail;
-int eval_glow_color;
-int eval_items2;
-int eval_scale;
-int eval_alpha;
-int eval_renderamt; // HalfLife support
-int eval_rendermode; // HalfLife support
-int eval_fullbright;
-int eval_ammo_shells1;
-int eval_ammo_nails1;
-int eval_ammo_lava_nails;
-int eval_ammo_rockets1;
-int eval_ammo_multi_rockets;
-int eval_ammo_cells1;
-int eval_ammo_plasma;
-int eval_idealpitch;
-int eval_pitch_speed;
-int eval_viewmodelforclient;
-int eval_nodrawtoclient;
-int eval_exteriormodeltoclient;
-int eval_drawonlytoclient;
-int eval_ping;
-int eval_movement;
-int eval_pmodel;
-int eval_punchvector;
-int eval_viewzoom;
-int eval_clientcolors;
-int eval_tag_entity;
-int eval_tag_index;
-int eval_light_lev;
-int eval_color;
-int eval_style;
-int eval_pflags;
-int eval_cursor_active;
-int eval_cursor_screen;
-int eval_cursor_trace_start;
-int eval_cursor_trace_endpos;
-int eval_cursor_trace_ent;
-int eval_colormod;
-int eval_playermodel;
-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");
- eval_button3 = PRVM_ED_FindFieldOffset("button3");
- eval_button4 = PRVM_ED_FindFieldOffset("button4");
- eval_button5 = PRVM_ED_FindFieldOffset("button5");
- eval_button6 = PRVM_ED_FindFieldOffset("button6");
- eval_button7 = PRVM_ED_FindFieldOffset("button7");
- eval_button8 = PRVM_ED_FindFieldOffset("button8");
- eval_button9 = PRVM_ED_FindFieldOffset("button9");
- eval_button10 = PRVM_ED_FindFieldOffset("button10");
- eval_button11 = PRVM_ED_FindFieldOffset("button11");
- eval_button12 = PRVM_ED_FindFieldOffset("button12");
- eval_button13 = PRVM_ED_FindFieldOffset("button13");
- eval_button14 = PRVM_ED_FindFieldOffset("button14");
- eval_button15 = PRVM_ED_FindFieldOffset("button15");
- eval_button16 = PRVM_ED_FindFieldOffset("button16");
- eval_buttonuse = PRVM_ED_FindFieldOffset("buttonuse");
- eval_buttonchat = PRVM_ED_FindFieldOffset("buttonchat");
- eval_glow_size = PRVM_ED_FindFieldOffset("glow_size");
- eval_glow_trail = PRVM_ED_FindFieldOffset("glow_trail");
- eval_glow_color = PRVM_ED_FindFieldOffset("glow_color");
- eval_items2 = PRVM_ED_FindFieldOffset("items2");
- eval_scale = PRVM_ED_FindFieldOffset("scale");
- eval_alpha = PRVM_ED_FindFieldOffset("alpha");
- eval_renderamt = PRVM_ED_FindFieldOffset("renderamt"); // HalfLife support
- eval_rendermode = PRVM_ED_FindFieldOffset("rendermode"); // HalfLife support
- eval_fullbright = PRVM_ED_FindFieldOffset("fullbright");
- eval_ammo_shells1 = PRVM_ED_FindFieldOffset("ammo_shells1");
- eval_ammo_nails1 = PRVM_ED_FindFieldOffset("ammo_nails1");
- eval_ammo_lava_nails = PRVM_ED_FindFieldOffset("ammo_lava_nails");
- eval_ammo_rockets1 = PRVM_ED_FindFieldOffset("ammo_rockets1");
- eval_ammo_multi_rockets = PRVM_ED_FindFieldOffset("ammo_multi_rockets");
- eval_ammo_cells1 = PRVM_ED_FindFieldOffset("ammo_cells1");
- eval_ammo_plasma = PRVM_ED_FindFieldOffset("ammo_plasma");
- eval_idealpitch = PRVM_ED_FindFieldOffset("idealpitch");
- eval_pitch_speed = PRVM_ED_FindFieldOffset("pitch_speed");
- eval_viewmodelforclient = PRVM_ED_FindFieldOffset("viewmodelforclient");
- eval_nodrawtoclient = PRVM_ED_FindFieldOffset("nodrawtoclient");
- eval_exteriormodeltoclient = PRVM_ED_FindFieldOffset("exteriormodeltoclient");
- eval_drawonlytoclient = PRVM_ED_FindFieldOffset("drawonlytoclient");
- eval_ping = PRVM_ED_FindFieldOffset("ping");
- eval_movement = PRVM_ED_FindFieldOffset("movement");
- eval_pmodel = PRVM_ED_FindFieldOffset("pmodel");
- eval_punchvector = PRVM_ED_FindFieldOffset("punchvector");
- eval_viewzoom = PRVM_ED_FindFieldOffset("viewzoom");
- eval_clientcolors = PRVM_ED_FindFieldOffset("clientcolors");
- eval_tag_entity = PRVM_ED_FindFieldOffset("tag_entity");
- eval_tag_index = PRVM_ED_FindFieldOffset("tag_index");
- eval_light_lev = PRVM_ED_FindFieldOffset("light_lev");
- eval_color = PRVM_ED_FindFieldOffset("color");
- eval_style = PRVM_ED_FindFieldOffset("style");
- eval_pflags = PRVM_ED_FindFieldOffset("pflags");
- eval_cursor_active = PRVM_ED_FindFieldOffset("cursor_active");
- eval_cursor_screen = PRVM_ED_FindFieldOffset("cursor_screen");
- eval_cursor_trace_start = PRVM_ED_FindFieldOffset("cursor_trace_start");
- eval_cursor_trace_endpos = PRVM_ED_FindFieldOffset("cursor_trace_endpos");
- eval_cursor_trace_ent = PRVM_ED_FindFieldOffset("cursor_trace_ent");
- eval_colormod = PRVM_ED_FindFieldOffset("colormod");
- eval_playermodel = PRVM_ED_FindFieldOffset("playermodel");
- eval_playerskin = PRVM_ED_FindFieldOffset("playerskin");
- 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");
- // LordHavoc: support for endframe
- 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))
prvm_required_field_t reqfields[] =
{ev_string, "playerskin"},
{ev_function, "SendEntity"},
{ev_function, "customizeentityforclient"},
+ // DRESK - Support for Entity Contents Transition Event
+ {ev_function, "contentstransition"},
};
void SV_VM_Setup(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;
+ size_t csprogsdatasize;
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;
prog->error_cmd = Host_Error;
// TODO: add a requiredfuncs list (ask LH if this is necessary at all)
- PRVM_LoadProgs( sv_progs.string, 0, NULL, REQFIELDS, reqfields );
- SV_VM_FindEdictFieldOffsets();
+ PRVM_LoadProgs( sv_progs.string, 0, NULL, REQFIELDS, reqfields, 0, NULL );
+
+ // some mods compiled with scrambling compilers lack certain critical
+ // global names and field names such as "self" and "time" and "nextthink"
+ // so we have to set these offsets manually, matching the entvars_t
+ PRVM_ED_FindFieldOffset_FromStruct(entvars_t, angles);
+ PRVM_ED_FindFieldOffset_FromStruct(entvars_t, chain);
+ PRVM_ED_FindFieldOffset_FromStruct(entvars_t, classname);
+ PRVM_ED_FindFieldOffset_FromStruct(entvars_t, frame);
+ PRVM_ED_FindFieldOffset_FromStruct(entvars_t, groundentity);
+ PRVM_ED_FindFieldOffset_FromStruct(entvars_t, ideal_yaw);
+ PRVM_ED_FindFieldOffset_FromStruct(entvars_t, nextthink);
+ PRVM_ED_FindFieldOffset_FromStruct(entvars_t, think);
+ PRVM_ED_FindFieldOffset_FromStruct(entvars_t, yaw_speed);
+ PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, self);
+ PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, time);
+ PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_forward);
+ PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_right);
+ PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_up);
+ PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_allsolid);
+ PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_startsolid);
+ PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_fraction);
+ PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_inwater);
+ PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_inopen);
+ PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_endpos);
+ PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_plane_normal);
+ PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_plane_dist);
+ PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_ent);
+ // OP_STATE is always supported on server (due to entvars_t)
+ prog->flag |= PRVM_OP_STATE;
VM_AutoSentStats_Clear();//[515]: csqc
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
+ sv.csqc_progname[0] = 0;
+ sv.csqc_progcrc = FS_CRCFile(csqc_progname.string, &csprogsdatasize);
+ sv.csqc_progsize = csprogsdatasize;
+ if (sv.csqc_progsize > 0)
+ {
+ strlcpy(sv.csqc_progname, csqc_progname.string, sizeof(sv.csqc_progname));
+ Con_DPrintf("server detected csqc progs file \"%s\" with size %i and crc %i\n", sv.csqc_progname, sv.csqc_progsize, sv.csqc_progcrc);
+ }
}
void SV_VM_Begin(void)
PRVM_Begin;
PRVM_SetProg( PRVM_SERVERPROG );
- *prog->time = (float) sv.time;
+ prog->globals.server->time = (float) sv.time;
}
void SV_VM_End(void)