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
+static cvar_t sv_cullentities_trace_samples = {0, "sv_cullentities_trace_samples", "1", "number of samples to test for entity culling"};
+static cvar_t sv_cullentities_trace_samples_extra = {0, "sv_cullentities_trace_samples_extra", "2", "number of samples to test for entity culling when the entity affects its surroundings by e.g. dlight"};
+static cvar_t sv_cullentities_trace_enlarge = {0, "sv_cullentities_trace_enlarge", "0", "box enlargement for entity culling"};
+static cvar_t sv_cullentities_trace_delay = {0, "sv_cullentities_trace_delay", "1", "number of seconds until the entity gets actually culled"};
+static cvar_t sv_cullentities_trace_prediction = {0, "sv_cullentities_trace_prediction", "1", "also trace from the predicted player position"};
+static 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!)"};
static cvar_t sv_cullentities_stats = {0, "sv_cullentities_stats", "0", "displays stats on network entities culled by various methods for each client"};
static cvar_t sv_entpatch = {0, "sv_entpatch", "1", "enables loading of .ent files to override entities in the bsp (for example Threewave CTF server pack contains .ent patch files enabling play of CTF on id1 maps)"};
Cvar_RegisterVariable (&sv_nostep);
Cvar_RegisterVariable (&sv_cullentities_pvs);
Cvar_RegisterVariable (&sv_cullentities_trace);
+ Cvar_RegisterVariable (&sv_cullentities_trace_samples);
+ Cvar_RegisterVariable (&sv_cullentities_trace_samples_extra);
+ Cvar_RegisterVariable (&sv_cullentities_trace_enlarge);
+ Cvar_RegisterVariable (&sv_cullentities_trace_delay);
+ Cvar_RegisterVariable (&sv_cullentities_trace_prediction);
+ Cvar_RegisterVariable (&sv_cullentities_nevercullbmodels);
Cvar_RegisterVariable (&sv_cullentities_stats);
Cvar_RegisterVariable (&sv_entpatch);
Cvar_RegisterVariable (&sv_gameplayfix_grenadebouncedownslopes);
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_GETGLOBALFIELDVALUE(prog->globaloffsets.SV_InitCmd);
+ val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.SV_InitCmd);
if (val)
{
MSG_WriteByte (&client->netconnection->message, svc_stufftext);
MSG_WriteString (&client->netconnection->message, "cl_serverextension_download 1");
}
+ // send at this time so it's guaranteed to get executed at the right time
+ {
+ client_t *save;
+ save = host_client;
+ host_client = client;
+ Curl_SendRequirements();
+ host_client = save;
+ }
+
MSG_WriteByte (&client->netconnection->message, svc_serverinfo);
MSG_WriteLong (&client->netconnection->message, Protocol_NumberForEnum(sv.protocol));
MSG_WriteByte (&client->netconnection->message, svs.maxclients);
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
+
+ // clear movement info until client enters the new level properly
+ memset(&client->cmd, 0, sizeof(client->cmd));
+ client->movesequence = 0;
+#ifdef NUM_PING_TIMES
+ for (i = 0;i < NUM_PING_TIMES;i++)
+ client->ping_times[i] = 0;
+ client->num_pings = 0;
+#endif
+ client->ping = 0;
}
/*
modelindex = (i >= 1 && i < MAX_MODELS && *PRVM_GetString(ent->fields.server->model)) ? i : 0;
flags = 0;
- i = (int)(PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.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, prog->fieldoffsets.glow_trail)->_float)
+ if (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.glow_trail)->_float)
flags |= RENDER_GLOWTRAIL;
- f = PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.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, prog->fieldoffsets.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, prog->fieldoffsets.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, prog->fieldoffsets.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, prog->fieldoffsets.style)->_float;
- lightpflags = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.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)
{
// early culling checks
// (final culling is done by SV_MarkWriteEntityStateToClient)
- customizeentityforclient = PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.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, prog->fieldoffsets.viewmodelforclient)->edict;
- cs->exteriormodelforclient = PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.exteriormodeltoclient)->edict;
- cs->nodrawtoclient = PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.nodrawtoclient)->edict;
- cs->drawonlytoclient = PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.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, prog->fieldoffsets.tag_entity)->edict;
- cs->tagindex = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.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, prog->fieldoffsets.colormod);
+ val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.colormod);
if (val->vector[0] || val->vector[1] || val->vector[2])
{
i = (int)(val->vector[0] * 32.0f);cs->colormod[0] = bound(0, i, 255);
cs->modelindex = modelindex;
cs->alpha = 255;
- f = (PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.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, prog->fieldoffsets.renderamt)->_float);
+ f = (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderamt)->_float);
if (f)
{
i = (int)f;
}
cs->scale = 16;
- f = (PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.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, prog->fieldoffsets.glow_color)->_float);
+ f = (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.glow_color)->_float);
if (f)
cs->glowcolor = (int)f;
- if (PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.fullbright)->_float)
+ if (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.fullbright)->_float)
cs->effects |= EF_FULLBRIGHT;
if (ent->fields.server->movetype == MOVETYPE_STEP)
cullmaxs[1] = max(cullmaxs[1], cs->origin[1] + specialvisibilityradius);
cullmaxs[2] = max(cullmaxs[2], cs->origin[2] + specialvisibilityradius);
}
+ // calculate center of bbox for network prioritization purposes
+ VectorMAM(0.5f, cullmins, 0.5f, cullmaxs, cs->netcenter);
+ // if culling box has moved, update pvs cluster links
if (!VectorCompare(cullmins, ent->priv.server->cullmins) || !VectorCompare(cullmaxs, ent->priv.server->cullmaxs))
{
VectorCopy(cullmins, ent->priv.server->cullmins);
VectorCopy(cullmaxs, ent->priv.server->cullmaxs);
+ // a value of -1 for pvs_numclusters indicates that the links are not
+ // cached, and should be re-tested each time, this is the case if the
+ // culling box touches too many pvs clusters to store, or if the world
+ // model does not support FindBoxClusters
ent->priv.server->pvs_numclusters = -1;
if (sv.worldmodel && sv.worldmodel->brush.FindBoxClusters)
{
void SV_MarkWriteEntityStateToClient(entity_state_t *s)
{
int isbmodel;
- vec3_t testorigin;
model_t *model;
prvm_edict_t *ed;
- trace_t trace;
if (sententitiesconsideration[s->number] == sententitiesmark)
return;
sententitiesconsideration[s->number] = sententitiesmark;
if (!s->modelindex && s->specialvisibilityradius == 0)
return;
+ isbmodel = (model = sv.models[s->modelindex]) != NULL && model->name[0] == '*';
// viewmodels don't have visibility checking
if (s->viewmodelforclient)
{
}
// always send world submodels in newer protocols because they don't
// generate much traffic (in old protocols they hog bandwidth)
- else if (!(s->effects & EF_NODEPTHTEST) && !((isbmodel = (model = sv.models[s->modelindex]) != NULL && model->name[0] == '*') && (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)))
+ // but only if sv_cullentities_alwayssendbmodels is on
+ else if (!(s->effects & EF_NODEPTHTEST) && (!isbmodel || !sv_cullentities_nevercullbmodels.integer || sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE))
{
// entity has survived every check so far, check if visible
ed = PRVM_EDICT_NUM(s->number);
// or not seen by random tracelines
if (sv_cullentities_trace.integer && !isbmodel)
{
- // LordHavoc: test center first
- 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, 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
+ int samples = s->specialvisibilityradius ? sv_cullentities_trace_samples_extra.integer : sv_cullentities_trace_samples.integer;
+ float enlarge = sv_cullentities_trace_enlarge.value;
+
+ qboolean visible = TRUE;
+
+ do
{
- // LordHavoc: test random offsets, to maximize chance of detection
- 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, 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
+ if(Mod_CanSeeBox_Trace(samples, enlarge, sv.worldmodel, sv_writeentitiestoclient_testeye, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
+ break; // directly visible from the server's view
+
+ if(sv_cullentities_trace_prediction.integer)
{
- if (s->specialvisibilityradius)
+ vec3_t predeye;
+
+ // get player velocity
+ float predtime = bound(0, host_client->ping, 0.2); // / 2
+ // sorry, no wallhacking by high ping please, and at 200ms
+ // ping a FPS is annoying to play anyway and a player is
+ // likely to have changed his direction
+ VectorMA(sv_writeentitiestoclient_testeye, predtime, host_client->edict->fields.server->velocity, predeye);
+ if(sv.worldmodel->brush.TraceLineOfSight(sv.worldmodel, sv_writeentitiestoclient_testeye, predeye)) // must be able to go there...
+ {
+ if(Mod_CanSeeBox_Trace(samples, enlarge, sv.worldmodel, predeye, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
+ break; // directly visible from the predicted view
+ }
+ else
{
- // LordHavoc: test random offsets, to maximize chance of detection
- 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, 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;
+ //Con_DPrintf("Trying to walk into solid in a pingtime... not predicting for culling\n");
}
}
+
+ // when we get here, we can't see the entity
+ visible = FALSE;
}
+ while(0);
+
+ if(visible)
+ sv_writeentitiestoclient_client->visibletime[s->number] = realtime + sv_cullentities_trace_delay.value;
+
if (realtime > sv_writeentitiestoclient_client->visibletime[s->number])
{
sv_writeentitiestoclient_culled_trace++;
}
entity_state_t sendstates[MAX_EDICTS];
-extern int csqc_clent;
+extern int csqc_clientnum;
void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t *msg, int *stats)
{
if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
sv_writeentitiestoclient_pvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, sv_writeentitiestoclient_testeye, 8, sv_writeentitiestoclient_pvs, sizeof(sv_writeentitiestoclient_pvs));
- csqc_clent = sv_writeentitiestoclient_clentnum = PRVM_EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes
+ sv_writeentitiestoclient_clentnum = PRVM_EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes
+ csqc_clientnum = sv_writeentitiestoclient_clentnum - 1;
sententitiesmark++;
// stuff the sigil bits into the high bits of items for sbar, or else
// mix in items2
- val = PRVM_GETEDICTFIELDVALUE(ent, prog->fieldoffsets.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, prog->fieldoffsets.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, prog->fieldoffsets.viewzoom)))
+ if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.viewzoom)))
viewzoom = (int)(val->_float * 255.0f);
if (viewzoom == 0)
viewzoom = 255;
// DP_SV_CLIENTCOLORS
// this is always found (since it's added by the progs loader)
- if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.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( prog->fieldoffsets.playermodel >= 0 ) {
- model = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string);
+ 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, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
+ PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
}
// NEXUIZ_PLAYERSKIN
if( prog->fieldoffsets.playerskin >= 0 ) {
- skin = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string);
+ 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, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
+ PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
}
// frags
return 0;
}
+// MUST match effectnameindex_t in client.h
+static const char *standardeffectnames[EFFECT_TOTAL] =
+{
+ "",
+ "TE_GUNSHOT",
+ "TE_GUNSHOTQUAD",
+ "TE_SPIKE",
+ "TE_SPIKEQUAD",
+ "TE_SUPERSPIKE",
+ "TE_SUPERSPIKEQUAD",
+ "TE_WIZSPIKE",
+ "TE_KNIGHTSPIKE",
+ "TE_EXPLOSION",
+ "TE_EXPLOSIONQUAD",
+ "TE_TAREXPLOSION",
+ "TE_TELEPORT",
+ "TE_LAVASPLASH",
+ "TE_SMALLFLASH",
+ "TE_FLAMEJET",
+ "EF_FLAME",
+ "TE_BLOOD",
+ "TE_SPARK",
+ "TE_PLASMABURN",
+ "TE_TEI_G3",
+ "TE_TEI_SMOKE",
+ "TE_TEI_BIGEXPLOSION",
+ "TE_TEI_PLASMAHIT",
+ "EF_STARDUST",
+ "TR_ROCKET",
+ "TR_GRENADE",
+ "TR_BLOOD",
+ "TR_WIZSPIKE",
+ "TR_SLIGHTBLOOD",
+ "TR_KNIGHTSPIKE",
+ "TR_VORESPIKE",
+ "TR_NEHAHRASMOKE",
+ "TR_NEXUIZPLASMA",
+ "TR_GLOWTRAIL",
+ "SVC_PARTICLE"
+};
+
+/*
+================
+SV_ParticleEffectIndex
+
+================
+*/
+int SV_ParticleEffectIndex(const char *name)
+{
+ int i, argc, linenumber, effectnameindex;
+ fs_offset_t filesize;
+ unsigned char *filedata;
+ const char *text, *textstart, *textend;
+ char argv[16][1024];
+ if (!sv.particleeffectnamesloaded)
+ {
+ sv.particleeffectnamesloaded = true;
+ memset(sv.particleeffectname, 0, sizeof(sv.particleeffectname));
+ for (i = 0;i < EFFECT_TOTAL;i++)
+ strlcpy(sv.particleeffectname[i], standardeffectnames[i], sizeof(sv.particleeffectname[i]));
+ filedata = FS_LoadFile("effectinfo.txt", tempmempool, true, &filesize);
+ if (filedata)
+ {
+ textstart = (const char *)filedata;
+ textend = (const char *)filedata + filesize;
+ text = textstart;
+ for (linenumber = 1;;linenumber++)
+ {
+ argc = 0;
+ for (;;)
+ {
+ if (!COM_ParseToken(&text, true) || !strcmp(com_token, "\n"))
+ break;
+ if (argc < 16)
+ {
+ strlcpy(argv[argc], com_token, sizeof(argv[argc]));
+ argc++;
+ }
+ }
+ if (com_token[0] == 0)
+ break; // if the loop exited and it's not a \n, it's EOF
+ if (argc < 1)
+ continue;
+ if (!strcmp(argv[0], "effect"))
+ {
+ if (argc == 2)
+ {
+ for (effectnameindex = 1;effectnameindex < SV_MAX_PARTICLEEFFECTNAME;effectnameindex++)
+ {
+ if (sv.particleeffectname[effectnameindex][0])
+ {
+ if (!strcmp(sv.particleeffectname[effectnameindex], argv[1]))
+ break;
+ }
+ else
+ {
+ strlcpy(sv.particleeffectname[effectnameindex], argv[1], sizeof(sv.particleeffectname[effectnameindex]));
+ break;
+ }
+ }
+ // if we run out of names, abort
+ if (effectnameindex == SV_MAX_PARTICLEEFFECTNAME)
+ {
+ Con_Printf("effectinfo.txt:%i: too many effects!\n", linenumber);
+ break;
+ }
+ }
+ }
+ }
+ Mem_Free(filedata);
+ }
+ }
+ // search for the name
+ for (effectnameindex = 1;effectnameindex < SV_MAX_PARTICLEEFFECTNAME && sv.particleeffectname[effectnameindex][0];effectnameindex++)
+ if (!strcmp(sv.particleeffectname[effectnameindex], name))
+ return effectnameindex;
+ // return 0 if we couldn't find it
+ return 0;
+}
+
/*
================
SV_CreateBaseline
// 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, prog->fieldoffsets.clientcolors)))
+ if ((val = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.clientcolors)))
val->_float = svs.clients[num].colors;
// NEXUIZ_PLAYERMODEL and NEXUIZ_PLAYERSKIN
if( prog->fieldoffsets.playermodel >= 0 )
- PRVM_GETEDICTFIELDVALUE(e, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(svs.clients[num].playermodel);
+ PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(svs.clients[num].playermodel);
if( prog->fieldoffsets.playerskin >= 0 )
- PRVM_GETEDICTFIELDVALUE(e, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(svs.clients[num].playerskin);
+ PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(svs.clients[num].playerskin);
}
}
// TODO: add a requiredfuncs list (ask LH if this is necessary at all)
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