2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 // sv_main.c -- server main program
27 void VM_AutoSentStats_Clear (void);
28 void EntityFrameCSQC_ClearVersions (void);
29 void EntityFrameCSQC_InitClientVersions (int client, qboolean clear);
30 void VM_SV_WriteAutoSentStats (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats);
31 void EntityFrameCSQC_WriteFrame (sizebuf_t *msg, int numstates, const entity_state_t *states);
34 // select which protocol to host, this is fed to Protocol_EnumForName
35 cvar_t sv_protocolname = {0, "sv_protocolname", "DP7", "selects network protocol to host for (values include QUAKE, QUAKEDP, NEHAHRAMOVIE, DP1 and up)"};
36 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)"};
37 cvar_t sv_maxrate = {CVAR_SAVE | CVAR_NOTIFY, "sv_maxrate", "10000", "upper limit on client rate cvar, should reflect your network connection quality"};
39 static cvar_t sv_cullentities_pvs = {0, "sv_cullentities_pvs", "1", "fast but loose culling of hidden entities"}; // fast but loose
40 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
41 static cvar_t sv_cullentities_stats = {0, "sv_cullentities_stats", "0", "displays stats on network entities culled by various methods for each client"};
42 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)"};
44 cvar_t sv_gameplayfix_grenadebouncedownslopes = {0, "sv_gameplayfix_grenadebouncedownslopes", "1", "prevents MOVETYPE_BOUNCE (grenades) from getting stuck when fired down a downward sloping surface"};
45 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"};
46 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)"};
47 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)"};
48 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"};
49 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"};
50 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"};
51 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"};
53 cvar_t sv_progs = {0, "sv_progs", "progs.dat", "selects which quakec progs.dat file to run" };
58 mempool_t *sv_mempool = NULL;
60 //============================================================================
62 extern void SV_Phys_Init (void);
63 extern void SV_World_Init (void);
64 static void SV_SaveEntFile_f(void);
73 Cmd_AddCommand("sv_saveentfile", SV_SaveEntFile_f, "save map entities to .ent file (to allow external editing)");
74 Cvar_RegisterVariable (&sv_maxvelocity);
75 Cvar_RegisterVariable (&sv_gravity);
76 Cvar_RegisterVariable (&sv_friction);
77 Cvar_RegisterVariable (&sv_edgefriction);
78 Cvar_RegisterVariable (&sv_stopspeed);
79 Cvar_RegisterVariable (&sv_maxspeed);
80 Cvar_RegisterVariable (&sv_maxairspeed);
81 Cvar_RegisterVariable (&sv_accelerate);
82 Cvar_RegisterVariable (&sv_idealpitchscale);
83 Cvar_RegisterVariable (&sv_aim);
84 Cvar_RegisterVariable (&sv_nostep);
85 Cvar_RegisterVariable (&sv_cullentities_pvs);
86 Cvar_RegisterVariable (&sv_cullentities_trace);
87 Cvar_RegisterVariable (&sv_cullentities_stats);
88 Cvar_RegisterVariable (&sv_entpatch);
89 Cvar_RegisterVariable (&sv_gameplayfix_grenadebouncedownslopes);
90 Cvar_RegisterVariable (&sv_gameplayfix_noairborncorpse);
91 Cvar_RegisterVariable (&sv_gameplayfix_stepdown);
92 Cvar_RegisterVariable (&sv_gameplayfix_stepwhilejumping);
93 Cvar_RegisterVariable (&sv_gameplayfix_swiminbmodels);
94 Cvar_RegisterVariable (&sv_gameplayfix_setmodelrealbox);
95 Cvar_RegisterVariable (&sv_gameplayfix_blowupfallenzombies);
96 Cvar_RegisterVariable (&sv_gameplayfix_findradiusdistancetobox);
97 Cvar_RegisterVariable (&sv_protocolname);
98 Cvar_RegisterVariable (&sv_ratelimitlocalplayer);
99 Cvar_RegisterVariable (&sv_maxrate);
100 Cvar_RegisterVariable (&sv_progs);
106 sv_mempool = Mem_AllocPool("server", 0, NULL);
109 static void SV_SaveEntFile_f(void)
111 char basename[MAX_QPATH];
112 if (!sv.active || !sv.worldmodel)
114 Con_Print("Not running a server\n");
117 FS_StripExtension(sv.worldmodel->name, basename, sizeof(basename));
118 FS_WriteFile(va("%s.ent", basename), sv.worldmodel->brush.entities, (fs_offset_t)strlen(sv.worldmodel->brush.entities));
123 =============================================================================
127 =============================================================================
134 Make sure the event gets sent to all clients
137 void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count)
141 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-18)
143 MSG_WriteByte (&sv.datagram, svc_particle);
144 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
145 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
146 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
147 for (i=0 ; i<3 ; i++)
154 MSG_WriteChar (&sv.datagram, v);
156 MSG_WriteByte (&sv.datagram, count);
157 MSG_WriteByte (&sv.datagram, color);
164 Make sure the event gets sent to all clients
167 void SV_StartEffect (vec3_t org, int modelindex, int startframe, int framecount, int framerate)
169 if (modelindex >= 256 || startframe >= 256)
171 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-19)
173 MSG_WriteByte (&sv.datagram, svc_effect2);
174 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
175 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
176 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
177 MSG_WriteShort (&sv.datagram, modelindex);
178 MSG_WriteShort (&sv.datagram, startframe);
179 MSG_WriteByte (&sv.datagram, framecount);
180 MSG_WriteByte (&sv.datagram, framerate);
184 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-17)
186 MSG_WriteByte (&sv.datagram, svc_effect);
187 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
188 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
189 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
190 MSG_WriteByte (&sv.datagram, modelindex);
191 MSG_WriteByte (&sv.datagram, startframe);
192 MSG_WriteByte (&sv.datagram, framecount);
193 MSG_WriteByte (&sv.datagram, framerate);
201 Each entity can have eight independant sound sources, like voice,
204 Channel 0 is an auto-allocate channel, the others override anything
205 already running on that entity/channel pair.
207 An attenuation of 0 will play full volume everywhere in the level.
208 Larger attenuations will drop off. (max 4 attenuation)
212 void SV_StartSound (prvm_edict_t *entity, int channel, const char *sample, int volume, float attenuation)
214 int sound_num, field_mask, i, ent;
216 if (volume < 0 || volume > 255)
218 Con_Printf ("SV_StartSound: volume = %i\n", volume);
222 if (attenuation < 0 || attenuation > 4)
224 Con_Printf ("SV_StartSound: attenuation = %f\n", attenuation);
228 if (channel < 0 || channel > 7)
230 Con_Printf ("SV_StartSound: channel = %i\n", channel);
234 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-21)
237 // find precache number for sound
238 sound_num = SV_SoundIndex(sample, 1);
242 ent = PRVM_NUM_FOR_EDICT(entity);
245 if (volume != DEFAULT_SOUND_PACKET_VOLUME)
246 field_mask |= SND_VOLUME;
247 if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
248 field_mask |= SND_ATTENUATION;
250 field_mask |= SND_LARGEENTITY;
251 if (sound_num >= 256 || channel >= 8)
252 field_mask |= SND_LARGESOUND;
254 // directed messages go only to the entity they are targeted on
255 MSG_WriteByte (&sv.datagram, svc_sound);
256 MSG_WriteByte (&sv.datagram, field_mask);
257 if (field_mask & SND_VOLUME)
258 MSG_WriteByte (&sv.datagram, volume);
259 if (field_mask & SND_ATTENUATION)
260 MSG_WriteByte (&sv.datagram, attenuation*64);
261 if (field_mask & SND_LARGEENTITY)
263 MSG_WriteShort (&sv.datagram, ent);
264 MSG_WriteByte (&sv.datagram, channel);
267 MSG_WriteShort (&sv.datagram, (ent<<3) | channel);
268 if (field_mask & SND_LARGESOUND)
269 MSG_WriteShort (&sv.datagram, sound_num);
271 MSG_WriteByte (&sv.datagram, sound_num);
272 for (i = 0;i < 3;i++)
273 MSG_WriteCoord (&sv.datagram, entity->fields.server->origin[i]+0.5*(entity->fields.server->mins[i]+entity->fields.server->maxs[i]), sv.protocol);
277 ==============================================================================
281 ==============================================================================
284 static const char *SV_InitCmd; //[515]: svprogs able to send cmd to client on connect
285 extern qboolean csqc_loaded;
290 Sends the first message from the server to a connected client.
291 This will be sent on the initial connection and upon each server load.
294 void SV_SendServerinfo (client_t *client)
299 // we know that this client has a netconnection and thus is not a bot
301 // edicts get reallocated on level changes, so we need to update it here
302 client->edict = PRVM_EDICT_NUM((client - svs.clients) + 1);
304 // clear cached stuff that depends on the level
305 client->weaponmodel[0] = 0;
306 client->weaponmodelindex = 0;
308 // LordHavoc: clear entityframe tracking
309 client->latestframenum = 0;
311 if (client->entitydatabase)
312 EntityFrame_FreeDatabase(client->entitydatabase);
313 if (client->entitydatabase4)
314 EntityFrame4_FreeDatabase(client->entitydatabase4);
315 if (client->entitydatabase5)
316 EntityFrame5_FreeDatabase(client->entitydatabase5);
318 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
320 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3)
321 client->entitydatabase = EntityFrame_AllocDatabase(sv_mempool);
322 else if (sv.protocol == PROTOCOL_DARKPLACES4)
323 client->entitydatabase4 = EntityFrame4_AllocDatabase(sv_mempool);
325 client->entitydatabase5 = EntityFrame5_AllocDatabase(sv_mempool);
328 SZ_Clear (&client->netconnection->message);
329 MSG_WriteByte (&client->netconnection->message, svc_print);
330 dpsnprintf (message, sizeof (message), "\002\nServer: %s build %s (progs %i crc)", gamename, buildstring, prog->filecrc);
331 MSG_WriteString (&client->netconnection->message,message);
333 // FIXME: LordHavoc: this does not work on dedicated servers, needs fixing.
334 //[515]: init csprogs according to version of svprogs, check the crc, etc.
335 if(csqc_loaded && (cls.state == ca_dedicated || PRVM_NUM_FOR_EDICT(client->edict) != 1))
337 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
339 MSG_WriteString (&client->netconnection->message, va("csqc_progcrc %i;%s\n", csqc_progcrc.integer, SV_InitCmd));
341 MSG_WriteString (&client->netconnection->message, va("csqc_progcrc %i\n", csqc_progcrc.integer));
344 MSG_WriteByte (&client->netconnection->message, svc_serverinfo);
345 MSG_WriteLong (&client->netconnection->message, Protocol_NumberForEnum(sv.protocol));
346 MSG_WriteByte (&client->netconnection->message, svs.maxclients);
348 if (!coop.integer && deathmatch.integer)
349 MSG_WriteByte (&client->netconnection->message, GAME_DEATHMATCH);
351 MSG_WriteByte (&client->netconnection->message, GAME_COOP);
353 MSG_WriteString (&client->netconnection->message,PRVM_GetString(prog->edicts->fields.server->message));
355 for (i = 1;i < MAX_MODELS && sv.model_precache[i][0];i++)
356 MSG_WriteString (&client->netconnection->message, sv.model_precache[i]);
357 MSG_WriteByte (&client->netconnection->message, 0);
359 for (i = 1;i < MAX_SOUNDS && sv.sound_precache[i][0];i++)
360 MSG_WriteString (&client->netconnection->message, sv.sound_precache[i]);
361 MSG_WriteByte (&client->netconnection->message, 0);
364 MSG_WriteByte (&client->netconnection->message, svc_cdtrack);
365 MSG_WriteByte (&client->netconnection->message, prog->edicts->fields.server->sounds);
366 MSG_WriteByte (&client->netconnection->message, prog->edicts->fields.server->sounds);
369 MSG_WriteByte (&client->netconnection->message, svc_setview);
370 MSG_WriteShort (&client->netconnection->message, PRVM_NUM_FOR_EDICT(client->edict));
372 MSG_WriteByte (&client->netconnection->message, svc_signonnum);
373 MSG_WriteByte (&client->netconnection->message, 1);
375 client->sendsignon = true;
376 client->spawned = false; // need prespawn, spawn, etc
383 Initializes a client_t for a new net connection. This will only be called
384 once for a player each game, not once for each level change.
387 void SV_ConnectClient (int clientnum, netconn_t *netconnection)
391 float spawn_parms[NUM_SPAWN_PARMS];
393 client = svs.clients + clientnum;
395 if(netconnection)//[515]: bots don't play with csqc =)
396 EntityFrameCSQC_InitClientVersions(clientnum, false);
398 // set up the client_t
400 memcpy (spawn_parms, client->spawn_parms, sizeof(spawn_parms));
401 memset (client, 0, sizeof(*client));
402 client->active = true;
403 client->netconnection = netconnection;
405 Con_DPrintf("Client %s connected\n", client->netconnection ? client->netconnection->address : "botclient");
407 strcpy(client->name, "unconnected");
408 strcpy(client->old_name, "unconnected");
409 client->spawned = false;
410 client->edict = PRVM_EDICT_NUM(clientnum+1);
411 client->netconnection->message.allowoverflow = true; // we can catch it
412 // updated by receiving "rate" command from client
413 client->rate = NET_MINRATE;
414 // no limits for local player
415 if (client->netconnection && LHNETADDRESS_GetAddressType(&client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP)
416 client->rate = 1000000000;
417 client->connecttime = realtime;
420 memcpy (client->spawn_parms, spawn_parms, sizeof(spawn_parms));
423 // call the progs to get default spawn parms for the new client
424 // set self to world to intentionally cause errors with broken SetNewParms code in some mods
425 prog->globals.server->self = 0;
426 PRVM_ExecuteProgram (prog->globals.server->SetNewParms, "QC function SetNewParms is missing");
427 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
428 client->spawn_parms[i] = (&prog->globals.server->parm1)[i];
431 // set up the entity for this client (including .colormap, .team, etc)
432 PRVM_ED_ClearEdict(client->edict);
434 // don't call SendServerinfo for a fresh botclient because its fields have
435 // not been set up by the qc yet
436 if (client->netconnection)
437 SV_SendServerinfo (client);
439 client->spawned = true;
444 ===============================================================================
448 ===============================================================================
457 void SV_ClearDatagram (void)
459 SZ_Clear (&sv.datagram);
463 =============================================================================
465 The PVS must include a small area around the client to allow head bobbing
466 or other small motion on the client side. Otherwise, a bob might cause an
467 entity that should be visible to not show up, especially when the bob
470 =============================================================================
473 int sv_writeentitiestoclient_pvsbytes;
474 unsigned char sv_writeentitiestoclient_pvs[MAX_MAP_LEAFS/8];
476 static int numsendentities;
477 static entity_state_t sendentities[MAX_EDICTS];
478 static entity_state_t *sendentitiesindex[MAX_EDICTS];
480 qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *cs, int e)
483 unsigned int modelindex, effects, flags, glowsize, lightstyle, lightpflags, light[4], specialvisibilityradius;
484 unsigned int customizeentityforclient;
486 vec3_t cullmins, cullmaxs;
490 // EF_NODRAW prevents sending for any reason except for your own
491 // client, so we must keep all clients in this superset
492 effects = (unsigned)ent->fields.server->effects;
494 // we can omit invisible entities with no effects that are not clients
495 // LordHavoc: this could kill tags attached to an invisible entity, I
496 // just hope we never have to support that case
497 i = (int)ent->fields.server->modelindex;
498 modelindex = (i >= 1 && i < MAX_MODELS && *PRVM_GetString(ent->fields.server->model)) ? i : 0;
501 i = (int)(PRVM_GETEDICTFIELDVALUE(ent, eval_glow_size)->_float * 0.25f);
502 glowsize = (unsigned char)bound(0, i, 255);
503 if (PRVM_GETEDICTFIELDVALUE(ent, eval_glow_trail)->_float)
504 flags |= RENDER_GLOWTRAIL;
506 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[0]*256;
507 light[0] = (unsigned short)bound(0, f, 65535);
508 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[1]*256;
509 light[1] = (unsigned short)bound(0, f, 65535);
510 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[2]*256;
511 light[2] = (unsigned short)bound(0, f, 65535);
512 f = PRVM_GETEDICTFIELDVALUE(ent, eval_light_lev)->_float;
513 light[3] = (unsigned short)bound(0, f, 65535);
514 lightstyle = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_style)->_float;
515 lightpflags = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_pflags)->_float;
517 if (gamemode == GAME_TENEBRAE)
519 // tenebrae's EF_FULLDYNAMIC conflicts with Q2's EF_NODRAW
523 lightpflags |= PFLAGS_FULLDYNAMIC;
525 // tenebrae's EF_GREEN conflicts with DP's EF_ADDITIVE
533 lightpflags |= PFLAGS_FULLDYNAMIC;
537 specialvisibilityradius = 0;
538 if (lightpflags & PFLAGS_FULLDYNAMIC)
539 specialvisibilityradius = max(specialvisibilityradius, light[3]);
541 specialvisibilityradius = max(specialvisibilityradius, glowsize * 4);
542 if (flags & RENDER_GLOWTRAIL)
543 specialvisibilityradius = max(specialvisibilityradius, 100);
544 if (effects & (EF_BRIGHTFIELD | EF_MUZZLEFLASH | EF_BRIGHTLIGHT | EF_DIMLIGHT | EF_RED | EF_BLUE | EF_FLAME | EF_STARDUST))
546 if (effects & EF_BRIGHTFIELD)
547 specialvisibilityradius = max(specialvisibilityradius, 80);
548 if (effects & EF_MUZZLEFLASH)
549 specialvisibilityradius = max(specialvisibilityradius, 100);
550 if (effects & EF_BRIGHTLIGHT)
551 specialvisibilityradius = max(specialvisibilityradius, 400);
552 if (effects & EF_DIMLIGHT)
553 specialvisibilityradius = max(specialvisibilityradius, 200);
554 if (effects & EF_RED)
555 specialvisibilityradius = max(specialvisibilityradius, 200);
556 if (effects & EF_BLUE)
557 specialvisibilityradius = max(specialvisibilityradius, 200);
558 if (effects & EF_FLAME)
559 specialvisibilityradius = max(specialvisibilityradius, 250);
560 if (effects & EF_STARDUST)
561 specialvisibilityradius = max(specialvisibilityradius, 100);
564 // early culling checks
565 // (final culling is done by SV_MarkWriteEntityStateToClient)
566 customizeentityforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_customizeentityforclient)->function;
567 if (!customizeentityforclient)
569 if (e > svs.maxclients && (!modelindex && !specialvisibilityradius))
571 // this 2 billion unit check is actually to detect NAN origins
572 // (we really don't want to send those)
573 if (VectorLength2(ent->fields.server->origin) > 2000000000.0*2000000000.0)
581 VectorCopy(ent->fields.server->origin, cs->origin);
582 VectorCopy(ent->fields.server->angles, cs->angles);
584 cs->effects = effects;
585 cs->colormap = (unsigned)ent->fields.server->colormap;
586 cs->modelindex = modelindex;
587 cs->skin = (unsigned)ent->fields.server->skin;
588 cs->frame = (unsigned)ent->fields.server->frame;
589 cs->viewmodelforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)->edict;
590 cs->exteriormodelforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_exteriormodeltoclient)->edict;
591 cs->nodrawtoclient = PRVM_GETEDICTFIELDVALUE(ent, eval_nodrawtoclient)->edict;
592 cs->drawonlytoclient = PRVM_GETEDICTFIELDVALUE(ent, eval_drawonlytoclient)->edict;
593 cs->customizeentityforclient = customizeentityforclient;
594 cs->tagentity = PRVM_GETEDICTFIELDVALUE(ent, eval_tag_entity)->edict;
595 cs->tagindex = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_tag_index)->_float;
596 cs->glowsize = glowsize;
598 // don't need to init cs->colormod because the defaultstate did that for us
599 //cs->colormod[0] = cs->colormod[1] = cs->colormod[2] = 32;
600 val = PRVM_GETEDICTFIELDVALUE(ent, eval_colormod);
601 if (val->vector[0] || val->vector[1] || val->vector[2])
603 i = val->vector[0] * 32.0f;cs->colormod[0] = bound(0, i, 255);
604 i = val->vector[1] * 32.0f;cs->colormod[1] = bound(0, i, 255);
605 i = val->vector[2] * 32.0f;cs->colormod[2] = bound(0, i, 255);
608 cs->modelindex = modelindex;
611 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_alpha)->_float * 255.0f);
615 cs->alpha = (unsigned char)bound(0, i, 255);
618 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_renderamt)->_float);
622 cs->alpha = (unsigned char)bound(0, i, 255);
626 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_scale)->_float * 16.0f);
630 cs->scale = (unsigned char)bound(0, i, 255);
634 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_glow_color)->_float);
636 cs->glowcolor = (int)f;
638 if (PRVM_GETEDICTFIELDVALUE(ent, eval_fullbright)->_float)
639 cs->effects |= EF_FULLBRIGHT;
641 if (ent->fields.server->movetype == MOVETYPE_STEP)
642 cs->flags |= RENDER_STEP;
643 if ((cs->effects & EF_LOWPRECISION) && cs->origin[0] >= -32768 && cs->origin[1] >= -32768 && cs->origin[2] >= -32768 && cs->origin[0] <= 32767 && cs->origin[1] <= 32767 && cs->origin[2] <= 32767)
644 cs->flags |= RENDER_LOWPRECISION;
645 if (ent->fields.server->colormap >= 1024)
646 cs->flags |= RENDER_COLORMAPPED;
647 if (cs->viewmodelforclient)
648 cs->flags |= RENDER_VIEWMODEL; // show relative to the view
650 cs->light[0] = light[0];
651 cs->light[1] = light[1];
652 cs->light[2] = light[2];
653 cs->light[3] = light[3];
654 cs->lightstyle = lightstyle;
655 cs->lightpflags = lightpflags;
657 cs->specialvisibilityradius = specialvisibilityradius;
659 // calculate the visible box of this entity (don't use the physics box
660 // as that is often smaller than a model, and would not count
661 // specialvisibilityradius)
662 if ((model = sv.models[modelindex]))
664 float scale = cs->scale * (1.0f / 16.0f);
665 if (cs->angles[0] || cs->angles[2]) // pitch and roll
667 VectorMA(cs->origin, scale, model->rotatedmins, cullmins);
668 VectorMA(cs->origin, scale, model->rotatedmaxs, cullmaxs);
670 else if (cs->angles[1])
672 VectorMA(cs->origin, scale, model->yawmins, cullmins);
673 VectorMA(cs->origin, scale, model->yawmaxs, cullmaxs);
677 VectorMA(cs->origin, scale, model->normalmins, cullmins);
678 VectorMA(cs->origin, scale, model->normalmaxs, cullmaxs);
683 VectorCopy(cs->origin, cullmins);
684 VectorCopy(cs->origin, cullmaxs);
686 if (specialvisibilityradius)
688 cullmins[0] = min(cullmins[0], cs->origin[0] - specialvisibilityradius);
689 cullmins[1] = min(cullmins[1], cs->origin[1] - specialvisibilityradius);
690 cullmins[2] = min(cullmins[2], cs->origin[2] - specialvisibilityradius);
691 cullmaxs[0] = max(cullmaxs[0], cs->origin[0] + specialvisibilityradius);
692 cullmaxs[1] = max(cullmaxs[1], cs->origin[1] + specialvisibilityradius);
693 cullmaxs[2] = max(cullmaxs[2], cs->origin[2] + specialvisibilityradius);
695 if (!VectorCompare(cullmins, ent->priv.server->cullmins) || !VectorCompare(cullmaxs, ent->priv.server->cullmaxs))
697 VectorCopy(cullmins, ent->priv.server->cullmins);
698 VectorCopy(cullmaxs, ent->priv.server->cullmaxs);
699 ent->priv.server->pvs_numclusters = -1;
700 if (sv.worldmodel && sv.worldmodel->brush.FindBoxClusters)
702 i = sv.worldmodel->brush.FindBoxClusters(sv.worldmodel, cullmins, cullmaxs, MAX_ENTITYCLUSTERS, ent->priv.server->pvs_clusterlist);
703 if (i <= MAX_ENTITYCLUSTERS)
704 ent->priv.server->pvs_numclusters = i;
711 void SV_PrepareEntitiesForSending(void)
715 // send all entities that touch the pvs
717 sendentitiesindex[0] = NULL;
718 memset(sendentitiesindex, 0, prog->num_edicts * sizeof(entity_state_t *));
719 for (e = 1, ent = PRVM_NEXT_EDICT(prog->edicts);e < prog->num_edicts;e++, ent = PRVM_NEXT_EDICT(ent))
721 if (!ent->priv.server->free && SV_PrepareEntityForSending(ent, sendentities + numsendentities, e))
723 sendentitiesindex[e] = sendentities + numsendentities;
729 static int sententitiesmark = 0;
730 static int sententities[MAX_EDICTS];
731 static int sententitiesconsideration[MAX_EDICTS];
732 static int sv_writeentitiestoclient_culled_pvs;
733 static int sv_writeentitiestoclient_culled_trace;
734 static int sv_writeentitiestoclient_visibleentities;
735 static int sv_writeentitiestoclient_totalentities;
736 //static entity_frame_t sv_writeentitiestoclient_entityframe;
737 static int sv_writeentitiestoclient_clentnum;
738 static vec3_t sv_writeentitiestoclient_testeye;
739 static client_t *sv_writeentitiestoclient_client;
741 void SV_MarkWriteEntityStateToClient(entity_state_t *s)
748 if (sententitiesconsideration[s->number] == sententitiesmark)
750 sententitiesconsideration[s->number] = sententitiesmark;
751 sv_writeentitiestoclient_totalentities++;
753 if (s->customizeentityforclient)
755 prog->globals.server->self = s->number;
756 prog->globals.server->other = sv_writeentitiestoclient_clentnum;
757 PRVM_ExecuteProgram(s->customizeentityforclient, "customizeentityforclient: NULL function");
758 if(!PRVM_G_FLOAT(OFS_RETURN) || !SV_PrepareEntityForSending(PRVM_EDICT_NUM(s->number), s, s->number))
762 // never reject player
763 if (s->number != sv_writeentitiestoclient_clentnum)
765 // check various rejection conditions
766 if (s->nodrawtoclient == sv_writeentitiestoclient_clentnum)
768 if (s->drawonlytoclient && s->drawonlytoclient != sv_writeentitiestoclient_clentnum)
770 if (s->effects & EF_NODRAW)
772 // LordHavoc: only send entities with a model or important effects
773 if (!s->modelindex && s->specialvisibilityradius == 0)
776 // viewmodels don't have visibility checking
777 if (s->viewmodelforclient)
779 if (s->viewmodelforclient != sv_writeentitiestoclient_clentnum)
782 else if (s->tagentity)
784 // tag attached entities simply check their parent
785 if (!sendentitiesindex[s->tagentity])
787 SV_MarkWriteEntityStateToClient(sendentitiesindex[s->tagentity]);
788 if (sententities[s->tagentity] != sententitiesmark)
791 // always send world submodels in newer protocols because they don't
792 // generate much traffic (in old protocols they hog bandwidth)
793 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)))
795 // entity has survived every check so far, check if visible
796 ed = PRVM_EDICT_NUM(s->number);
798 // if not touching a visible leaf
799 if (sv_cullentities_pvs.integer && sv_writeentitiestoclient_pvsbytes)
801 if (ed->priv.server->pvs_numclusters < 0)
803 // entity too big for clusters list
804 if (sv.worldmodel && sv.worldmodel->brush.BoxTouchingPVS && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, sv_writeentitiestoclient_pvs, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
806 sv_writeentitiestoclient_culled_pvs++;
813 // check cached clusters list
814 for (i = 0;i < ed->priv.server->pvs_numclusters;i++)
815 if (CHECKPVSBIT(sv_writeentitiestoclient_pvs, ed->priv.server->pvs_clusterlist[i]))
817 if (i == ed->priv.server->pvs_numclusters)
819 sv_writeentitiestoclient_culled_pvs++;
825 // or not seen by random tracelines
826 if (sv_cullentities_trace.integer && !isbmodel)
828 // LordHavoc: test center first
829 testorigin[0] = (ed->priv.server->cullmins[0] + ed->priv.server->cullmaxs[0]) * 0.5f;
830 testorigin[1] = (ed->priv.server->cullmins[1] + ed->priv.server->cullmaxs[1]) * 0.5f;
831 testorigin[2] = (ed->priv.server->cullmins[2] + ed->priv.server->cullmaxs[2]) * 0.5f;
832 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, sv_writeentitiestoclient_testeye, testorigin, testorigin, SUPERCONTENTS_SOLID);
833 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
834 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
837 // LordHavoc: test random offsets, to maximize chance of detection
838 testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]);
839 testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]);
840 testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]);
841 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, sv_writeentitiestoclient_testeye, testorigin, testorigin, SUPERCONTENTS_SOLID);
842 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
843 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
846 if (s->specialvisibilityradius)
848 // LordHavoc: test random offsets, to maximize chance of detection
849 testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]);
850 testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]);
851 testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]);
852 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, sv_writeentitiestoclient_testeye, testorigin, testorigin, SUPERCONTENTS_SOLID);
853 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
854 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
858 if (realtime > sv_writeentitiestoclient_client->visibletime[s->number])
860 sv_writeentitiestoclient_culled_trace++;
867 // this just marks it for sending
868 // FIXME: it would be more efficient to send here, but the entity
869 // compressor isn't that flexible
870 sv_writeentitiestoclient_visibleentities++;
871 sententities[s->number] = sententitiesmark;
874 entity_state_t sendstates[MAX_EDICTS];
875 extern int csqc_clent;
877 void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t *msg, int *stats)
879 int i, numsendstates;
882 // if there isn't enough space to accomplish anything, skip it
883 if (msg->cursize + 25 > msg->maxsize)
886 sv_writeentitiestoclient_client = client;
888 sv_writeentitiestoclient_culled_pvs = 0;
889 sv_writeentitiestoclient_culled_trace = 0;
890 sv_writeentitiestoclient_visibleentities = 0;
891 sv_writeentitiestoclient_totalentities = 0;
893 // find the client's PVS
894 // the real place being tested from
895 VectorAdd(clent->fields.server->origin, clent->fields.server->view_ofs, sv_writeentitiestoclient_testeye);
896 sv_writeentitiestoclient_pvsbytes = 0;
897 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
898 sv_writeentitiestoclient_pvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, sv_writeentitiestoclient_testeye, 8, sv_writeentitiestoclient_pvs, sizeof(sv_writeentitiestoclient_pvs));
900 csqc_clent = sv_writeentitiestoclient_clentnum = PRVM_EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes
904 for (i = 0;i < numsendentities;i++)
905 SV_MarkWriteEntityStateToClient(sendentities + i);
908 for (i = 0;i < numsendentities;i++)
910 if (sententities[sendentities[i].number] == sententitiesmark)
912 s = &sendstates[numsendstates++];
913 *s = sendentities[i];
914 if (s->exteriormodelforclient && s->exteriormodelforclient == sv_writeentitiestoclient_clentnum)
915 s->flags |= RENDER_EXTERIORMODEL;
919 if (sv_cullentities_stats.integer)
920 Con_Printf("client \"%s\" entities: %d total, %d visible, %d culled by: %d pvs %d trace\n", client->name, sv_writeentitiestoclient_totalentities, sv_writeentitiestoclient_visibleentities, sv_writeentitiestoclient_culled_pvs + sv_writeentitiestoclient_culled_trace, sv_writeentitiestoclient_culled_pvs, sv_writeentitiestoclient_culled_trace);
922 EntityFrameCSQC_WriteFrame(msg, numsendstates, sendstates);
924 if (client->entitydatabase5)
925 EntityFrame5_WriteFrame(msg, client->entitydatabase5, numsendstates, sendstates, client - svs.clients + 1, stats, client->movesequence);
926 else if (client->entitydatabase4)
927 EntityFrame4_WriteFrame(msg, client->entitydatabase4, numsendstates, sendstates);
928 else if (client->entitydatabase)
929 EntityFrame_WriteFrame(msg, client->entitydatabase, numsendstates, sendstates, client - svs.clients + 1);
931 EntityFrameQuake_WriteFrame(msg, numsendstates, sendstates);
940 void SV_CleanupEnts (void)
945 ent = PRVM_NEXT_EDICT(prog->edicts);
946 for (e=1 ; e<prog->num_edicts ; e++, ent = PRVM_NEXT_EDICT(ent))
947 ent->fields.server->effects = (int)ent->fields.server->effects & ~EF_MUZZLEFLASH;
952 SV_WriteClientdataToMessage
956 void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
964 unsigned char viewzoom;
968 // send a damage message
970 if (ent->fields.server->dmg_take || ent->fields.server->dmg_save)
972 other = PRVM_PROG_TO_EDICT(ent->fields.server->dmg_inflictor);
973 MSG_WriteByte (msg, svc_damage);
974 MSG_WriteByte (msg, ent->fields.server->dmg_save);
975 MSG_WriteByte (msg, ent->fields.server->dmg_take);
976 for (i=0 ; i<3 ; i++)
977 MSG_WriteCoord (msg, other->fields.server->origin[i] + 0.5*(other->fields.server->mins[i] + other->fields.server->maxs[i]), sv.protocol);
979 ent->fields.server->dmg_take = 0;
980 ent->fields.server->dmg_save = 0;
984 // send the current viewpos offset from the view entity
986 SV_SetIdealPitch (); // how much to look up / down ideally
988 // a fixangle might get lost in a dropped packet. Oh well.
989 if ( ent->fields.server->fixangle )
991 MSG_WriteByte (msg, svc_setangle);
992 for (i=0 ; i < 3 ; i++)
993 MSG_WriteAngle (msg, ent->fields.server->angles[i], sv.protocol);
994 ent->fields.server->fixangle = 0;
997 // stuff the sigil bits into the high bits of items for sbar, or else
999 val = PRVM_GETEDICTFIELDVALUE(ent, eval_items2);
1000 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
1001 items = (int)ent->fields.server->items | ((int)val->_float << 23);
1003 items = (int)ent->fields.server->items | ((int)prog->globals.server->serverflags << 28);
1005 VectorClear(punchvector);
1006 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_punchvector)))
1007 VectorCopy(val->vector, punchvector);
1009 // cache weapon model name and index in client struct to save time
1010 // (this search can be almost 1% of cpu time!)
1011 s = PRVM_GetString(ent->fields.server->weaponmodel);
1012 if (strcmp(s, client->weaponmodel))
1014 strlcpy(client->weaponmodel, s, sizeof(client->weaponmodel));
1015 client->weaponmodelindex = SV_ModelIndex(s, 1);
1019 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_viewzoom)))
1020 viewzoom = val->_float * 255.0f;
1026 if ((int)ent->fields.server->flags & FL_ONGROUND)
1027 bits |= SU_ONGROUND;
1028 if (ent->fields.server->waterlevel >= 2)
1030 if (ent->fields.server->idealpitch)
1031 bits |= SU_IDEALPITCH;
1033 for (i=0 ; i<3 ; i++)
1035 if (ent->fields.server->punchangle[i])
1036 bits |= (SU_PUNCH1<<i);
1037 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
1039 bits |= (SU_PUNCHVEC1<<i);
1040 if (ent->fields.server->velocity[i])
1041 bits |= (SU_VELOCITY1<<i);
1044 memset(stats, 0, sizeof(int[MAX_CL_STATS]));
1045 stats[STAT_VIEWHEIGHT] = ent->fields.server->view_ofs[2];
1046 stats[STAT_ITEMS] = items;
1047 stats[STAT_WEAPONFRAME] = ent->fields.server->weaponframe;
1048 stats[STAT_ARMOR] = ent->fields.server->armorvalue;
1049 stats[STAT_WEAPON] = client->weaponmodelindex;
1050 stats[STAT_HEALTH] = ent->fields.server->health;
1051 stats[STAT_AMMO] = ent->fields.server->currentammo;
1052 stats[STAT_SHELLS] = ent->fields.server->ammo_shells;
1053 stats[STAT_NAILS] = ent->fields.server->ammo_nails;
1054 stats[STAT_ROCKETS] = ent->fields.server->ammo_rockets;
1055 stats[STAT_CELLS] = ent->fields.server->ammo_cells;
1056 stats[STAT_ACTIVEWEAPON] = ent->fields.server->weapon;
1057 stats[STAT_VIEWZOOM] = viewzoom;
1058 // the QC bumps these itself by sending svc_'s, so we have to keep them
1059 // zero or they'll be corrected by the engine
1060 //stats[STAT_TOTALSECRETS] = prog->globals.server->total_secrets;
1061 //stats[STAT_TOTALMONSTERS] = prog->globals.server->total_monsters;
1062 //stats[STAT_SECRETS] = prog->globals.server->found_secrets;
1063 //stats[STAT_MONSTERS] = prog->globals.server->killed_monsters;
1065 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 || sv.protocol == PROTOCOL_DARKPLACES5)
1067 if (stats[STAT_VIEWHEIGHT] != DEFAULT_VIEWHEIGHT) bits |= SU_VIEWHEIGHT;
1069 if (stats[STAT_WEAPONFRAME]) bits |= SU_WEAPONFRAME;
1070 if (stats[STAT_ARMOR]) bits |= SU_ARMOR;
1072 // FIXME: which protocols support this? does PROTOCOL_DARKPLACES3 support viewzoom?
1073 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
1074 if (viewzoom != 255)
1075 bits |= SU_VIEWZOOM;
1080 if (bits >= 16777216)
1084 MSG_WriteByte (msg, svc_clientdata);
1085 MSG_WriteShort (msg, bits);
1086 if (bits & SU_EXTEND1)
1087 MSG_WriteByte(msg, bits >> 16);
1088 if (bits & SU_EXTEND2)
1089 MSG_WriteByte(msg, bits >> 24);
1091 if (bits & SU_VIEWHEIGHT)
1092 MSG_WriteChar (msg, stats[STAT_VIEWHEIGHT]);
1094 if (bits & SU_IDEALPITCH)
1095 MSG_WriteChar (msg, ent->fields.server->idealpitch);
1097 for (i=0 ; i<3 ; i++)
1099 if (bits & (SU_PUNCH1<<i))
1101 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1102 MSG_WriteChar(msg, ent->fields.server->punchangle[i]);
1104 MSG_WriteAngle16i(msg, ent->fields.server->punchangle[i]);
1106 if (bits & (SU_PUNCHVEC1<<i))
1108 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1109 MSG_WriteCoord16i(msg, punchvector[i]);
1111 MSG_WriteCoord32f(msg, punchvector[i]);
1113 if (bits & (SU_VELOCITY1<<i))
1115 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1116 MSG_WriteChar(msg, ent->fields.server->velocity[i] * (1.0f / 16.0f));
1118 MSG_WriteCoord32f(msg, ent->fields.server->velocity[i]);
1122 if (bits & SU_ITEMS)
1123 MSG_WriteLong (msg, stats[STAT_ITEMS]);
1125 if (sv.protocol == PROTOCOL_DARKPLACES5)
1127 if (bits & SU_WEAPONFRAME)
1128 MSG_WriteShort (msg, stats[STAT_WEAPONFRAME]);
1129 if (bits & SU_ARMOR)
1130 MSG_WriteShort (msg, stats[STAT_ARMOR]);
1131 if (bits & SU_WEAPON)
1132 MSG_WriteShort (msg, stats[STAT_WEAPON]);
1133 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1134 MSG_WriteShort (msg, stats[STAT_AMMO]);
1135 MSG_WriteShort (msg, stats[STAT_SHELLS]);
1136 MSG_WriteShort (msg, stats[STAT_NAILS]);
1137 MSG_WriteShort (msg, stats[STAT_ROCKETS]);
1138 MSG_WriteShort (msg, stats[STAT_CELLS]);
1139 MSG_WriteShort (msg, stats[STAT_ACTIVEWEAPON]);
1140 if (bits & SU_VIEWZOOM)
1141 MSG_WriteShort (msg, min(stats[STAT_VIEWZOOM], 65535));
1143 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)
1145 if (bits & SU_WEAPONFRAME)
1146 MSG_WriteByte (msg, stats[STAT_WEAPONFRAME]);
1147 if (bits & SU_ARMOR)
1148 MSG_WriteByte (msg, stats[STAT_ARMOR]);
1149 if (bits & SU_WEAPON)
1150 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1151 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1152 MSG_WriteByte (msg, stats[STAT_AMMO]);
1153 MSG_WriteByte (msg, stats[STAT_SHELLS]);
1154 MSG_WriteByte (msg, stats[STAT_NAILS]);
1155 MSG_WriteByte (msg, stats[STAT_ROCKETS]);
1156 MSG_WriteByte (msg, stats[STAT_CELLS]);
1157 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_NEXUIZ)
1159 for (i = 0;i < 32;i++)
1160 if (stats[STAT_WEAPON] & (1<<i))
1162 MSG_WriteByte (msg, i);
1165 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1166 if (bits & SU_VIEWZOOM)
1168 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1169 MSG_WriteByte (msg, min(stats[STAT_VIEWZOOM], 255));
1171 MSG_WriteShort (msg, min(stats[STAT_VIEWZOOM], 65535));
1177 =======================
1178 SV_SendClientDatagram
1179 =======================
1181 static unsigned char sv_sendclientdatagram_buf[NET_MAXMESSAGE]; // FIXME?
1182 qboolean SV_SendClientDatagram (client_t *client)
1184 int rate, maxrate, maxsize, maxsize2;
1186 int stats[MAX_CL_STATS];
1188 if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP && !sv_ratelimitlocalplayer.integer)
1190 // for good singleplayer, send huge packets
1191 maxsize = sizeof(sv_sendclientdatagram_buf);
1192 maxsize2 = sizeof(sv_sendclientdatagram_buf);
1194 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)
1196 // no rate limiting support on older protocols because dp protocols
1197 // 1-4 kick the client off if they overflow, and quake protocol shows
1198 // less than the full entity set if rate limited
1204 // PROTOCOL_DARKPLACES5 and later support packet size limiting of updates
1205 maxrate = bound(NET_MINRATE, sv_maxrate.integer, NET_MAXRATE);
1206 if (sv_maxrate.integer != maxrate)
1207 Cvar_SetValueQuick(&sv_maxrate, maxrate);
1209 rate = bound(NET_MINRATE, client->rate, maxrate);
1210 rate = (int)(client->rate * sys_ticrate.value);
1211 maxsize = bound(100, rate, 1400);
1215 msg.data = sv_sendclientdatagram_buf;
1216 msg.maxsize = maxsize;
1219 MSG_WriteByte (&msg, svc_time);
1220 MSG_WriteFloat (&msg, sv.time);
1222 // add the client specific data to the datagram
1223 SV_WriteClientdataToMessage (client, client->edict, &msg, stats);
1224 VM_SV_WriteAutoSentStats (client, client->edict, &msg, stats);
1225 SV_WriteEntitiesToClient (client, client->edict, &msg, stats);
1227 // expand packet size to allow effects to go over the rate limit
1228 // (dropping them is FAR too ugly)
1229 msg.maxsize = maxsize2;
1231 // copy the server datagram if there is space
1232 // FIXME: put in delayed queue of effects to send
1233 if (sv.datagram.cursize > 0 && msg.cursize + sv.datagram.cursize <= msg.maxsize)
1234 SZ_Write (&msg, sv.datagram.data, sv.datagram.cursize);
1236 // send the datagram
1237 if (NetConn_SendUnreliableMessage (client->netconnection, &msg) == -1)
1239 SV_DropClient (true);// if the message couldn't send, kick off
1247 =======================
1248 SV_UpdateToReliableMessages
1249 =======================
1251 void SV_UpdateToReliableMessages (void)
1260 // check for changes to be sent over the reliable streams
1261 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1263 // update the host_client fields we care about according to the entity fields
1264 host_client->edict = PRVM_EDICT_NUM(i+1);
1267 name = PRVM_GetString(host_client->edict->fields.server->netname);
1270 // always point the string back at host_client->name to keep it safe
1271 strlcpy (host_client->name, name, sizeof (host_client->name));
1272 host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
1273 if (strcmp(host_client->old_name, host_client->name))
1275 if (host_client->spawned)
1276 SV_BroadcastPrintf("%s changed name to %s\n", host_client->old_name, host_client->name);
1277 strcpy(host_client->old_name, host_client->name);
1278 // send notification to all clients
1279 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
1280 MSG_WriteByte (&sv.reliable_datagram, i);
1281 MSG_WriteString (&sv.reliable_datagram, host_client->name);
1284 // DP_SV_CLIENTCOLORS
1285 // this is always found (since it's added by the progs loader)
1286 if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_clientcolors)))
1287 host_client->colors = (int)val->_float;
1288 if (host_client->old_colors != host_client->colors)
1290 host_client->old_colors = host_client->colors;
1291 // send notification to all clients
1292 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1293 MSG_WriteByte (&sv.reliable_datagram, i);
1294 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1297 // NEXUIZ_PLAYERMODEL
1298 if( eval_playermodel ) {
1299 model = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string);
1302 // always point the string back at host_client->name to keep it safe
1303 strlcpy (host_client->playermodel, model, sizeof (host_client->playermodel));
1304 PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
1307 // NEXUIZ_PLAYERSKIN
1308 if( eval_playerskin ) {
1309 skin = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string);
1312 // always point the string back at host_client->name to keep it safe
1313 strlcpy (host_client->playerskin, skin, sizeof (host_client->playerskin));
1314 PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
1318 host_client->frags = (int)host_client->edict->fields.server->frags;
1319 if (host_client->old_frags != host_client->frags)
1321 host_client->old_frags = host_client->frags;
1322 // send notification to all clients
1323 MSG_WriteByte (&sv.reliable_datagram, svc_updatefrags);
1324 MSG_WriteByte (&sv.reliable_datagram, i);
1325 MSG_WriteShort (&sv.reliable_datagram, host_client->frags);
1329 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1330 if (client->netconnection)
1331 SZ_Write (&client->netconnection->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
1333 SZ_Clear (&sv.reliable_datagram);
1338 =======================
1341 Send a nop message without trashing or sending the accumulated client
1343 =======================
1345 void SV_SendNop (client_t *client)
1348 unsigned char buf[4];
1351 msg.maxsize = sizeof(buf);
1354 MSG_WriteChar (&msg, svc_nop);
1356 if (NetConn_SendUnreliableMessage (client->netconnection, &msg) == -1)
1357 SV_DropClient (true); // if the message couldn't send, kick off
1358 client->last_message = realtime;
1362 =======================
1363 SV_SendClientMessages
1364 =======================
1366 void SV_SendClientMessages (void)
1368 int i, prepared = false;
1370 // update frags, names, etc
1371 SV_UpdateToReliableMessages();
1373 // build individual updates
1374 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1376 if (!host_client->active)
1378 if (!host_client->netconnection)
1381 if (host_client->netconnection->message.overflowed)
1383 SV_DropClient (true); // if the message couldn't send, kick off
1387 if (host_client->spawned)
1392 // only prepare entities once per frame
1393 SV_PrepareEntitiesForSending();
1395 if (!SV_SendClientDatagram (host_client))
1400 // the player isn't totally in the game yet
1401 // send small keepalive messages if too much time has passed
1402 // send a full message when the next signon stage has been requested
1403 // some other message data (name changes, etc) may accumulate
1404 // between signon stages
1405 if (!host_client->sendsignon)
1407 if (realtime - host_client->last_message > 5)
1408 SV_SendNop (host_client);
1409 continue; // don't send out non-signon messages
1413 if (host_client->netconnection->message.cursize)
1415 if (!NetConn_CanSendMessage (host_client->netconnection))
1418 if (NetConn_SendReliableMessage (host_client->netconnection, &host_client->netconnection->message) == -1)
1419 SV_DropClient (true); // if the message couldn't send, kick off
1420 SZ_Clear (&host_client->netconnection->message);
1421 host_client->last_message = realtime;
1422 host_client->sendsignon = false;
1426 // clear muzzle flashes
1432 ==============================================================================
1436 ==============================================================================
1445 int SV_ModelIndex(const char *s, int precachemode)
1447 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_MODELS);
1448 char filename[MAX_QPATH];
1452 //if (precachemode == 2)
1454 strlcpy(filename, s, sizeof(filename));
1455 for (i = 2;i < limit;i++)
1457 if (!sv.model_precache[i][0])
1461 if (sv.state != ss_loading && (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 || sv.protocol == PROTOCOL_DARKPLACES5))
1463 Con_Printf("SV_ModelIndex(\"%s\"): precache_model can only be done in spawn functions\n", filename);
1466 if (precachemode == 1)
1467 Con_Printf("SV_ModelIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1468 strlcpy(sv.model_precache[i], filename, sizeof(sv.model_precache[i]));
1469 sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, false);
1470 if (sv.state != ss_loading)
1472 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1473 MSG_WriteShort(&sv.reliable_datagram, i);
1474 MSG_WriteString(&sv.reliable_datagram, filename);
1478 Con_Printf("SV_ModelIndex(\"%s\"): not precached\n", filename);
1481 if (!strcmp(sv.model_precache[i], filename))
1484 Con_Printf("SV_ModelIndex(\"%s\"): i (%i) == MAX_MODELS (%i)\n", filename, i, MAX_MODELS);
1494 int SV_SoundIndex(const char *s, int precachemode)
1496 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_SOUNDS);
1497 char filename[MAX_QPATH];
1501 //if (precachemode == 2)
1503 strlcpy(filename, s, sizeof(filename));
1504 for (i = 1;i < limit;i++)
1506 if (!sv.sound_precache[i][0])
1510 if (sv.state != ss_loading && (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 || sv.protocol == PROTOCOL_DARKPLACES5))
1512 Con_Printf("SV_SoundIndex(\"%s\"): precache_sound can only be done in spawn functions\n", filename);
1515 if (precachemode == 1)
1516 Con_Printf("SV_SoundIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1517 strlcpy(sv.sound_precache[i], filename, sizeof(sv.sound_precache[i]));
1518 if (sv.state != ss_loading)
1520 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1521 MSG_WriteShort(&sv.reliable_datagram, i + 32768);
1522 MSG_WriteString(&sv.reliable_datagram, filename);
1526 Con_Printf("SV_SoundIndex(\"%s\"): not precached\n", filename);
1529 if (!strcmp(sv.sound_precache[i], filename))
1532 Con_Printf("SV_SoundIndex(\"%s\"): i (%i) == MAX_SOUNDS (%i)\n", filename, i, MAX_SOUNDS);
1542 void SV_CreateBaseline (void)
1544 int i, entnum, large;
1545 prvm_edict_t *svent;
1547 // LordHavoc: clear *all* states (note just active ones)
1548 for (entnum = 0;entnum < prog->max_edicts;entnum++)
1550 // get the current server version
1551 svent = PRVM_EDICT_NUM(entnum);
1553 // LordHavoc: always clear state values, whether the entity is in use or not
1554 svent->priv.server->baseline = defaultstate;
1556 if (svent->priv.server->free)
1558 if (entnum > svs.maxclients && !svent->fields.server->modelindex)
1561 // create entity baseline
1562 VectorCopy (svent->fields.server->origin, svent->priv.server->baseline.origin);
1563 VectorCopy (svent->fields.server->angles, svent->priv.server->baseline.angles);
1564 svent->priv.server->baseline.frame = svent->fields.server->frame;
1565 svent->priv.server->baseline.skin = svent->fields.server->skin;
1566 if (entnum > 0 && entnum <= svs.maxclients)
1568 svent->priv.server->baseline.colormap = entnum;
1569 svent->priv.server->baseline.modelindex = SV_ModelIndex("progs/player.mdl", 1);
1573 svent->priv.server->baseline.colormap = 0;
1574 svent->priv.server->baseline.modelindex = svent->fields.server->modelindex;
1578 if (svent->priv.server->baseline.modelindex & 0xFF00 || svent->priv.server->baseline.frame & 0xFF00)
1581 // add to the message
1583 MSG_WriteByte (&sv.signon, svc_spawnbaseline2);
1585 MSG_WriteByte (&sv.signon, svc_spawnbaseline);
1586 MSG_WriteShort (&sv.signon, entnum);
1590 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.modelindex);
1591 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.frame);
1595 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.modelindex);
1596 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.frame);
1598 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.colormap);
1599 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.skin);
1600 for (i=0 ; i<3 ; i++)
1602 MSG_WriteCoord(&sv.signon, svent->priv.server->baseline.origin[i], sv.protocol);
1603 MSG_WriteAngle(&sv.signon, svent->priv.server->baseline.angles[i], sv.protocol);
1613 Tell all the clients that the server is changing levels
1616 void SV_SendReconnect (void)
1619 MSG_WriteByte(&sv.reliable_datagram, svc_stufftext);
1620 MSG_WriteString(&sv.reliable_datagram, "reconnect\n");
1622 unsigned char data[128];
1627 msg.maxsize = sizeof(data);
1629 MSG_WriteChar (&msg, svc_stufftext);
1630 MSG_WriteString (&msg, "reconnect\n");
1631 NetConn_SendToAll (&msg, 5);
1633 if (cls.state != ca_dedicated)
1634 Cmd_ExecuteString ("reconnect\n", src_command);
1643 Grabs the current state of each client for saving across the
1644 transition to another level
1647 void SV_SaveSpawnparms (void)
1651 svs.serverflags = prog->globals.server->serverflags;
1653 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1655 if (!host_client->active)
1658 // call the progs to get default spawn parms for the new client
1659 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1660 PRVM_ExecuteProgram (prog->globals.server->SetChangeParms, "QC function SetChangeParms is missing");
1661 for (j=0 ; j<NUM_SPAWN_PARMS ; j++)
1662 host_client->spawn_parms[j] = (&prog->globals.server->parm1)[j];
1666 void SV_IncreaseEdicts(void)
1670 int oldmax_edicts = prog->max_edicts;
1671 void *oldedictsengineprivate = prog->edictprivate;
1672 void *oldedictsfields = prog->edictsfields;
1673 void *oldmoved_edicts = sv.moved_edicts;
1675 if (prog->max_edicts >= MAX_EDICTS)
1678 // links don't survive the transition, so unlink everything
1679 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1681 if (!ent->priv.server->free)
1682 SV_UnlinkEdict(prog->edicts + i);
1683 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
1687 prog->max_edicts = min(prog->max_edicts + 256, MAX_EDICTS);
1688 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
1689 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);
1690 sv.moved_edicts = PR_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1692 memcpy(prog->edictprivate, oldedictsengineprivate, oldmax_edicts * sizeof(edict_engineprivate_t));
1693 memcpy(prog->edictsfields, oldedictsfields, oldmax_edicts * prog->edict_size);
1695 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1697 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
1698 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
1699 // link every entity except world
1700 if (!ent->priv.server->free)
1701 SV_LinkEdict(ent, false);
1704 PR_Free(oldedictsengineprivate);
1705 PR_Free(oldedictsfields);
1706 PR_Free(oldmoved_edicts);
1713 This is called at the start of each level
1716 extern float scr_centertime_off;
1718 void SV_SpawnServer (const char *server)
1723 model_t *worldmodel;
1724 char modelname[sizeof(sv.modelname)];
1726 Con_DPrintf("SpawnServer: %s\n", server);
1728 if (cls.state != ca_dedicated)
1729 SCR_BeginLoadingPlaque();
1731 dpsnprintf (modelname, sizeof(modelname), "maps/%s.bsp", server);
1732 worldmodel = Mod_ForName(modelname, false, true, true);
1733 if (!worldmodel || !worldmodel->TraceBox)
1735 Con_Printf("Couldn't load map %s\n", modelname);
1739 // let's not have any servers with no name
1740 if (hostname.string[0] == 0)
1741 Cvar_Set ("hostname", "UNNAMED");
1742 scr_centertime_off = 0;
1744 svs.changelevel_issued = false; // now safe to issue another
1747 // tell all connected clients that we are going to a new level
1758 NetConn_OpenServerPorts(true);
1762 // make cvars consistant
1765 Cvar_SetValue ("deathmatch", 0);
1766 // LordHavoc: it can be useful to have skills outside the range 0-3...
1767 //current_skill = bound(0, (int)(skill.value + 0.5), 3);
1768 //Cvar_SetValue ("skill", (float)current_skill);
1769 current_skill = (int)(skill.value + 0.5);
1772 // set up the new server
1774 Host_ClearMemory ();
1776 memset (&sv, 0, sizeof(sv));
1782 strlcpy (sv.name, server, sizeof (sv.name));
1784 sv.protocol = Protocol_EnumForName(sv_protocolname.string);
1785 if (sv.protocol == PROTOCOL_UNKNOWN)
1788 Protocol_Names(buffer, sizeof(buffer));
1789 Con_Printf("Unknown sv_protocolname \"%s\", valid values are:\n%s\n", sv_protocolname.string, buffer);
1790 sv.protocol = PROTOCOL_QUAKE;
1795 // load progs to get entity field count
1796 //PR_LoadProgs ( sv_progs.string );
1798 // allocate server memory
1799 /*// start out with just enough room for clients and a reasonable estimate of entities
1800 prog->max_edicts = max(svs.maxclients + 1, 512);
1801 prog->max_edicts = min(prog->max_edicts, MAX_EDICTS);
1803 // prvm_edict_t structures (hidden from progs)
1804 prog->edicts = PR_Alloc(MAX_EDICTS * sizeof(prvm_edict_t));
1805 // engine private structures (hidden from progs)
1806 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
1807 // progs fields, often accessed by server
1808 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);*/
1809 // used by PushMove to move back pushed entities
1810 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1811 /*for (i = 0;i < prog->max_edicts;i++)
1813 ent = prog->edicts + i;
1814 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
1815 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
1818 // reset client csqc entity versions right away.
1819 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1820 EntityFrameCSQC_InitClientVersions(i, true);
1822 sv.datagram.maxsize = sizeof(sv.datagram_buf);
1823 sv.datagram.cursize = 0;
1824 sv.datagram.data = sv.datagram_buf;
1826 sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf);
1827 sv.reliable_datagram.cursize = 0;
1828 sv.reliable_datagram.data = sv.reliable_datagram_buf;
1830 sv.signon.maxsize = sizeof(sv.signon_buf);
1831 sv.signon.cursize = 0;
1832 sv.signon.data = sv.signon_buf;
1834 // leave slots at start for clients only
1835 //prog->num_edicts = svs.maxclients+1;
1837 sv.state = ss_loading;
1838 prog->allowworldwrites = true;
1841 *prog->time = sv.time = 1.0;
1844 worldmodel->used = true;
1846 strlcpy (sv.name, server, sizeof (sv.name));
1847 strcpy(sv.modelname, modelname);
1848 sv.worldmodel = worldmodel;
1849 sv.models[1] = sv.worldmodel;
1852 // clear world interaction links
1856 strlcpy(sv.sound_precache[0], "", sizeof(sv.sound_precache[0]));
1858 strlcpy(sv.model_precache[0], "", sizeof(sv.model_precache[0]));
1859 strlcpy(sv.model_precache[1], sv.modelname, sizeof(sv.model_precache[1]));
1860 for (i = 1;i < sv.worldmodel->brush.numsubmodels;i++)
1862 dpsnprintf(sv.model_precache[i+1], sizeof(sv.model_precache[i+1]), "*%i", i);
1863 sv.models[i+1] = Mod_ForName (sv.model_precache[i+1], false, false, false);
1867 // load the rest of the entities
1869 // AK possible hack since num_edicts is still 0
1870 ent = PRVM_EDICT_NUM(0);
1871 memset (ent->fields.server, 0, prog->progs->entityfields * 4);
1872 ent->priv.server->free = false;
1873 ent->fields.server->model = PRVM_SetEngineString(sv.modelname);
1874 ent->fields.server->modelindex = 1; // world model
1875 ent->fields.server->solid = SOLID_BSP;
1876 ent->fields.server->movetype = MOVETYPE_PUSH;
1879 prog->globals.server->coop = coop.integer;
1881 prog->globals.server->deathmatch = deathmatch.integer;
1883 prog->globals.server->mapname = PRVM_SetEngineString(sv.name);
1885 // serverflags are for cross level information (sigils)
1886 prog->globals.server->serverflags = svs.serverflags;
1888 // we need to reset the spawned flag on all connected clients here so that
1889 // their thinks don't run during startup (before PutClientInServer)
1890 // we also need to set up the client entities now
1891 // and we need to set the ->edict pointers to point into the progs edicts
1892 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1894 host_client->spawned = false;
1895 host_client->edict = PRVM_EDICT_NUM(i + 1);
1896 PRVM_ED_ClearEdict(host_client->edict);
1899 // load replacement entity file if found
1901 if (sv_entpatch.integer)
1902 entities = (char *)FS_LoadFile(va("maps/%s.ent", sv.name), tempmempool, true, NULL);
1905 Con_Printf("Loaded maps/%s.ent\n", sv.name);
1906 PRVM_ED_LoadFromFile (entities);
1910 PRVM_ED_LoadFromFile (sv.worldmodel->brush.entities);
1913 // LordHavoc: clear world angles (to fix e3m3.bsp)
1914 VectorClear(prog->edicts->fields.server->angles);
1916 // all setup is completed, any further precache statements are errors
1917 sv.state = ss_active;
1918 prog->allowworldwrites = false;
1920 // run two frames to allow everything to settle
1921 for (i = 0;i < 2;i++)
1923 sv.frametime = host_frametime = 0.1;
1929 // create a baseline for more efficient communications
1930 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1931 SV_CreateBaseline ();
1933 // send serverinfo to all connected clients, and set up botclients coming back from a level change
1934 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1936 if (!host_client->active)
1938 if (host_client->netconnection)
1939 SV_SendServerinfo(host_client);
1943 // if client is a botclient coming from a level change, we need to
1944 // set up client info that normally requires networking
1946 // copy spawn parms out of the client_t
1947 for (j=0 ; j< NUM_SPAWN_PARMS ; j++)
1948 (&prog->globals.server->parm1)[j] = host_client->spawn_parms[j];
1950 // call the spawn function
1951 host_client->clientconnectcalled = true;
1952 prog->globals.server->time = sv.time;
1953 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1954 PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
1955 PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
1956 host_client->spawned = true;
1960 Con_DPrint("Server spawned.\n");
1961 NetConn_Heartbeat (2);
1966 /////////////////////////////////////////////////////
1969 void SV_VM_CB_BeginIncreaseEdicts(void)
1974 PRVM_Free( sv.moved_edicts );
1975 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1977 // links don't survive the transition, so unlink everything
1978 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1980 if (!ent->priv.server->free)
1981 SV_UnlinkEdict(prog->edicts + i);
1982 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
1987 void SV_VM_CB_EndIncreaseEdicts(void)
1992 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1994 // link every entity except world
1995 if (!ent->priv.server->free)
1996 SV_LinkEdict(ent, false);
2000 void SV_VM_CB_InitEdict(prvm_edict_t *e)
2002 // LordHavoc: for consistency set these here
2003 int num = PRVM_NUM_FOR_EDICT(e) - 1;
2005 if (num >= 0 && num < svs.maxclients)
2008 // set colormap and team on newly created player entity
2009 e->fields.server->colormap = num + 1;
2010 e->fields.server->team = (svs.clients[num].colors & 15) + 1;
2011 // set netname/clientcolors back to client values so that
2012 // DP_SV_CLIENTNAME and DP_SV_CLIENTCOLORS will not immediately
2014 e->fields.server->netname = PRVM_SetEngineString(svs.clients[num].name);
2015 if ((val = PRVM_GETEDICTFIELDVALUE(e, eval_clientcolors)))
2016 val->_float = svs.clients[num].colors;
2017 // NEXUIZ_PLAYERMODEL and NEXUIZ_PLAYERSKIN
2018 if( eval_playermodel )
2019 PRVM_GETEDICTFIELDVALUE(e, eval_playermodel)->string = PRVM_SetEngineString(svs.clients[num].playermodel);
2020 if( eval_playerskin )
2021 PRVM_GETEDICTFIELDVALUE(e, eval_playerskin)->string = PRVM_SetEngineString(svs.clients[num].playerskin);
2025 void SV_VM_CB_FreeEdict(prvm_edict_t *ed)
2027 SV_UnlinkEdict (ed); // unlink from world bsp
2029 ed->fields.server->model = 0;
2030 ed->fields.server->takedamage = 0;
2031 ed->fields.server->modelindex = 0;
2032 ed->fields.server->colormap = 0;
2033 ed->fields.server->skin = 0;
2034 ed->fields.server->frame = 0;
2035 VectorClear(ed->fields.server->origin);
2036 VectorClear(ed->fields.server->angles);
2037 ed->fields.server->nextthink = -1;
2038 ed->fields.server->solid = 0;
2041 void SV_VM_CB_CountEdicts(void)
2045 int active, models, solid, step;
2047 active = models = solid = step = 0;
2048 for (i=0 ; i<prog->num_edicts ; i++)
2050 ent = PRVM_EDICT_NUM(i);
2051 if (ent->priv.server->free)
2054 if (ent->fields.server->solid)
2056 if (ent->fields.server->model)
2058 if (ent->fields.server->movetype == MOVETYPE_STEP)
2062 Con_Printf("num_edicts:%3i\n", prog->num_edicts);
2063 Con_Printf("active :%3i\n", active);
2064 Con_Printf("view :%3i\n", models);
2065 Con_Printf("touch :%3i\n", solid);
2066 Con_Printf("step :%3i\n", step);
2069 qboolean SV_VM_CB_LoadEdict(prvm_edict_t *ent)
2071 // remove things from different skill levels or deathmatch
2072 if (gamemode != GAME_TRANSFUSION) //Transfusion does this in QC
2074 if (deathmatch.integer)
2076 if (((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
2081 else if ((current_skill <= 0 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_EASY ))
2082 || (current_skill == 1 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_MEDIUM))
2083 || (current_skill >= 2 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_HARD )))
2091 cvar_t pr_checkextension = {CVAR_READONLY, "pr_checkextension", "1", "indicates to QuakeC that the standard quakec extensions system is available (if 0, quakec should not attempt to use extensions)"};
2092 cvar_t nomonsters = {0, "nomonsters", "0", "unused cvar in quake, can be used by mods"};
2093 cvar_t gamecfg = {0, "gamecfg", "0", "unused cvar in quake, can be used by mods"};
2094 cvar_t scratch1 = {0, "scratch1", "0", "unused cvar in quake, can be used by mods"};
2095 cvar_t scratch2 = {0,"scratch2", "0", "unused cvar in quake, can be used by mods"};
2096 cvar_t scratch3 = {0, "scratch3", "0", "unused cvar in quake, can be used by mods"};
2097 cvar_t scratch4 = {0, "scratch4", "0", "unused cvar in quake, can be used by mods"};
2098 cvar_t savedgamecfg = {CVAR_SAVE, "savedgamecfg", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2099 cvar_t saved1 = {CVAR_SAVE, "saved1", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2100 cvar_t saved2 = {CVAR_SAVE, "saved2", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2101 cvar_t saved3 = {CVAR_SAVE, "saved3", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2102 cvar_t saved4 = {CVAR_SAVE, "saved4", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2103 cvar_t nehx00 = {0, "nehx00", "0", "nehahra data storage cvar (used in singleplayer)"};
2104 cvar_t nehx01 = {0, "nehx01", "0", "nehahra data storage cvar (used in singleplayer)"};
2105 cvar_t nehx02 = {0, "nehx02", "0", "nehahra data storage cvar (used in singleplayer)"};
2106 cvar_t nehx03 = {0, "nehx03", "0", "nehahra data storage cvar (used in singleplayer)"};
2107 cvar_t nehx04 = {0, "nehx04", "0", "nehahra data storage cvar (used in singleplayer)"};
2108 cvar_t nehx05 = {0, "nehx05", "0", "nehahra data storage cvar (used in singleplayer)"};
2109 cvar_t nehx06 = {0, "nehx06", "0", "nehahra data storage cvar (used in singleplayer)"};
2110 cvar_t nehx07 = {0, "nehx07", "0", "nehahra data storage cvar (used in singleplayer)"};
2111 cvar_t nehx08 = {0, "nehx08", "0", "nehahra data storage cvar (used in singleplayer)"};
2112 cvar_t nehx09 = {0, "nehx09", "0", "nehahra data storage cvar (used in singleplayer)"};
2113 cvar_t nehx10 = {0, "nehx10", "0", "nehahra data storage cvar (used in singleplayer)"};
2114 cvar_t nehx11 = {0, "nehx11", "0", "nehahra data storage cvar (used in singleplayer)"};
2115 cvar_t nehx12 = {0, "nehx12", "0", "nehahra data storage cvar (used in singleplayer)"};
2116 cvar_t nehx13 = {0, "nehx13", "0", "nehahra data storage cvar (used in singleplayer)"};
2117 cvar_t nehx14 = {0, "nehx14", "0", "nehahra data storage cvar (used in singleplayer)"};
2118 cvar_t nehx15 = {0, "nehx15", "0", "nehahra data storage cvar (used in singleplayer)"};
2119 cvar_t nehx16 = {0, "nehx16", "0", "nehahra data storage cvar (used in singleplayer)"};
2120 cvar_t nehx17 = {0, "nehx17", "0", "nehahra data storage cvar (used in singleplayer)"};
2121 cvar_t nehx18 = {0, "nehx18", "0", "nehahra data storage cvar (used in singleplayer)"};
2122 cvar_t nehx19 = {0, "nehx19", "0", "nehahra data storage cvar (used in singleplayer)"};
2123 cvar_t cutscene = {0, "cutscene", "1", "enables cutscenes in nehahra, can be used by other mods"};
2125 void SV_VM_Init(void)
2127 Cvar_RegisterVariable (&pr_checkextension);
2128 Cvar_RegisterVariable (&nomonsters);
2129 Cvar_RegisterVariable (&gamecfg);
2130 Cvar_RegisterVariable (&scratch1);
2131 Cvar_RegisterVariable (&scratch2);
2132 Cvar_RegisterVariable (&scratch3);
2133 Cvar_RegisterVariable (&scratch4);
2134 Cvar_RegisterVariable (&savedgamecfg);
2135 Cvar_RegisterVariable (&saved1);
2136 Cvar_RegisterVariable (&saved2);
2137 Cvar_RegisterVariable (&saved3);
2138 Cvar_RegisterVariable (&saved4);
2139 // LordHavoc: Nehahra uses these to pass data around cutscene demos
2140 if (gamemode == GAME_NEHAHRA)
2142 Cvar_RegisterVariable (&nehx00);
2143 Cvar_RegisterVariable (&nehx01);
2144 Cvar_RegisterVariable (&nehx02);
2145 Cvar_RegisterVariable (&nehx03);
2146 Cvar_RegisterVariable (&nehx04);
2147 Cvar_RegisterVariable (&nehx05);
2148 Cvar_RegisterVariable (&nehx06);
2149 Cvar_RegisterVariable (&nehx07);
2150 Cvar_RegisterVariable (&nehx08);
2151 Cvar_RegisterVariable (&nehx09);
2152 Cvar_RegisterVariable (&nehx10);
2153 Cvar_RegisterVariable (&nehx11);
2154 Cvar_RegisterVariable (&nehx12);
2155 Cvar_RegisterVariable (&nehx13);
2156 Cvar_RegisterVariable (&nehx14);
2157 Cvar_RegisterVariable (&nehx15);
2158 Cvar_RegisterVariable (&nehx16);
2159 Cvar_RegisterVariable (&nehx17);
2160 Cvar_RegisterVariable (&nehx18);
2161 Cvar_RegisterVariable (&nehx19);
2163 Cvar_RegisterVariable (&cutscene); // for Nehahra but useful to other mods as well
2166 // LordHavoc: in an effort to eliminate time wasted on GetEdictFieldValue... these are defined as externs in progs.h
2183 int eval_buttonchat;
2185 int eval_glow_trail;
2186 int eval_glow_color;
2190 int eval_renderamt; // HalfLife support
2191 int eval_rendermode; // HalfLife support
2192 int eval_fullbright;
2193 int eval_ammo_shells1;
2194 int eval_ammo_nails1;
2195 int eval_ammo_lava_nails;
2196 int eval_ammo_rockets1;
2197 int eval_ammo_multi_rockets;
2198 int eval_ammo_cells1;
2199 int eval_ammo_plasma;
2200 int eval_idealpitch;
2201 int eval_pitch_speed;
2202 int eval_viewmodelforclient;
2203 int eval_nodrawtoclient;
2204 int eval_exteriormodeltoclient;
2205 int eval_drawonlytoclient;
2209 int eval_punchvector;
2211 int eval_clientcolors;
2212 int eval_tag_entity;
2218 int eval_cursor_active;
2219 int eval_cursor_screen;
2220 int eval_cursor_trace_start;
2221 int eval_cursor_trace_endpos;
2222 int eval_cursor_trace_ent;
2224 int eval_playermodel;
2225 int eval_playerskin;
2226 int eval_SendEntity;
2228 int eval_customizeentityforclient;
2230 mfunction_t *SV_PlayerPhysicsQC;
2231 mfunction_t *EndFrameQC;
2232 //KrimZon - SERVER COMMANDS IN QUAKEC
2233 mfunction_t *SV_ParseClientCommandQC;
2235 ddef_t *PRVM_ED_FindGlobal(const char *name);
2237 void SV_VM_FindEdictFieldOffsets(void)
2239 eval_gravity = PRVM_ED_FindFieldOffset("gravity");
2240 eval_button3 = PRVM_ED_FindFieldOffset("button3");
2241 eval_button4 = PRVM_ED_FindFieldOffset("button4");
2242 eval_button5 = PRVM_ED_FindFieldOffset("button5");
2243 eval_button6 = PRVM_ED_FindFieldOffset("button6");
2244 eval_button7 = PRVM_ED_FindFieldOffset("button7");
2245 eval_button8 = PRVM_ED_FindFieldOffset("button8");
2246 eval_button9 = PRVM_ED_FindFieldOffset("button9");
2247 eval_button10 = PRVM_ED_FindFieldOffset("button10");
2248 eval_button11 = PRVM_ED_FindFieldOffset("button11");
2249 eval_button12 = PRVM_ED_FindFieldOffset("button12");
2250 eval_button13 = PRVM_ED_FindFieldOffset("button13");
2251 eval_button14 = PRVM_ED_FindFieldOffset("button14");
2252 eval_button15 = PRVM_ED_FindFieldOffset("button15");
2253 eval_button16 = PRVM_ED_FindFieldOffset("button16");
2254 eval_buttonuse = PRVM_ED_FindFieldOffset("buttonuse");
2255 eval_buttonchat = PRVM_ED_FindFieldOffset("buttonchat");
2256 eval_glow_size = PRVM_ED_FindFieldOffset("glow_size");
2257 eval_glow_trail = PRVM_ED_FindFieldOffset("glow_trail");
2258 eval_glow_color = PRVM_ED_FindFieldOffset("glow_color");
2259 eval_items2 = PRVM_ED_FindFieldOffset("items2");
2260 eval_scale = PRVM_ED_FindFieldOffset("scale");
2261 eval_alpha = PRVM_ED_FindFieldOffset("alpha");
2262 eval_renderamt = PRVM_ED_FindFieldOffset("renderamt"); // HalfLife support
2263 eval_rendermode = PRVM_ED_FindFieldOffset("rendermode"); // HalfLife support
2264 eval_fullbright = PRVM_ED_FindFieldOffset("fullbright");
2265 eval_ammo_shells1 = PRVM_ED_FindFieldOffset("ammo_shells1");
2266 eval_ammo_nails1 = PRVM_ED_FindFieldOffset("ammo_nails1");
2267 eval_ammo_lava_nails = PRVM_ED_FindFieldOffset("ammo_lava_nails");
2268 eval_ammo_rockets1 = PRVM_ED_FindFieldOffset("ammo_rockets1");
2269 eval_ammo_multi_rockets = PRVM_ED_FindFieldOffset("ammo_multi_rockets");
2270 eval_ammo_cells1 = PRVM_ED_FindFieldOffset("ammo_cells1");
2271 eval_ammo_plasma = PRVM_ED_FindFieldOffset("ammo_plasma");
2272 eval_idealpitch = PRVM_ED_FindFieldOffset("idealpitch");
2273 eval_pitch_speed = PRVM_ED_FindFieldOffset("pitch_speed");
2274 eval_viewmodelforclient = PRVM_ED_FindFieldOffset("viewmodelforclient");
2275 eval_nodrawtoclient = PRVM_ED_FindFieldOffset("nodrawtoclient");
2276 eval_exteriormodeltoclient = PRVM_ED_FindFieldOffset("exteriormodeltoclient");
2277 eval_drawonlytoclient = PRVM_ED_FindFieldOffset("drawonlytoclient");
2278 eval_ping = PRVM_ED_FindFieldOffset("ping");
2279 eval_movement = PRVM_ED_FindFieldOffset("movement");
2280 eval_pmodel = PRVM_ED_FindFieldOffset("pmodel");
2281 eval_punchvector = PRVM_ED_FindFieldOffset("punchvector");
2282 eval_viewzoom = PRVM_ED_FindFieldOffset("viewzoom");
2283 eval_clientcolors = PRVM_ED_FindFieldOffset("clientcolors");
2284 eval_tag_entity = PRVM_ED_FindFieldOffset("tag_entity");
2285 eval_tag_index = PRVM_ED_FindFieldOffset("tag_index");
2286 eval_light_lev = PRVM_ED_FindFieldOffset("light_lev");
2287 eval_color = PRVM_ED_FindFieldOffset("color");
2288 eval_style = PRVM_ED_FindFieldOffset("style");
2289 eval_pflags = PRVM_ED_FindFieldOffset("pflags");
2290 eval_cursor_active = PRVM_ED_FindFieldOffset("cursor_active");
2291 eval_cursor_screen = PRVM_ED_FindFieldOffset("cursor_screen");
2292 eval_cursor_trace_start = PRVM_ED_FindFieldOffset("cursor_trace_start");
2293 eval_cursor_trace_endpos = PRVM_ED_FindFieldOffset("cursor_trace_endpos");
2294 eval_cursor_trace_ent = PRVM_ED_FindFieldOffset("cursor_trace_ent");
2295 eval_colormod = PRVM_ED_FindFieldOffset("colormod");
2296 eval_playermodel = PRVM_ED_FindFieldOffset("playermodel");
2297 eval_playerskin = PRVM_ED_FindFieldOffset("playerskin");
2298 eval_SendEntity = PRVM_ED_FindFieldOffset("SendEntity");
2299 eval_Version = PRVM_ED_FindFieldOffset("Version");
2300 eval_customizeentityforclient = PRVM_ED_FindFieldOffset("customizeentityforclient");
2302 // LordHavoc: allowing QuakeC to override the player movement code
2303 SV_PlayerPhysicsQC = PRVM_ED_FindFunction ("SV_PlayerPhysics");
2304 // LordHavoc: support for endframe
2305 EndFrameQC = PRVM_ED_FindFunction ("EndFrame");
2306 //KrimZon - SERVER COMMANDS IN QUAKEC
2307 SV_ParseClientCommandQC = PRVM_ED_FindFunction ("SV_ParseClientCommand");
2309 //[515]: init stufftext string (it is sent before svc_serverinfo)
2310 if(PRVM_ED_FindGlobal("SV_InitCmd") && PRVM_ED_FindGlobal("SV_InitCmd")->type & ev_string)
2311 SV_InitCmd = PRVM_G_STRING(PRVM_ED_FindGlobal("SV_InitCmd")->ofs);
2316 #define REQFIELDS (sizeof(reqfields) / sizeof(prvm_required_field_t))
2318 prvm_required_field_t reqfields[] =
2320 {ev_entity, "cursor_trace_ent"},
2321 {ev_entity, "drawonlytoclient"},
2322 {ev_entity, "exteriormodeltoclient"},
2323 {ev_entity, "nodrawtoclient"},
2324 {ev_entity, "tag_entity"},
2325 {ev_entity, "viewmodelforclient"},
2326 {ev_float, "alpha"},
2327 {ev_float, "ammo_cells1"},
2328 {ev_float, "ammo_lava_nails"},
2329 {ev_float, "ammo_multi_rockets"},
2330 {ev_float, "ammo_nails1"},
2331 {ev_float, "ammo_plasma"},
2332 {ev_float, "ammo_rockets1"},
2333 {ev_float, "ammo_shells1"},
2334 {ev_float, "button3"},
2335 {ev_float, "button4"},
2336 {ev_float, "button5"},
2337 {ev_float, "button6"},
2338 {ev_float, "button7"},
2339 {ev_float, "button8"},
2340 {ev_float, "button9"},
2341 {ev_float, "button10"},
2342 {ev_float, "button11"},
2343 {ev_float, "button12"},
2344 {ev_float, "button13"},
2345 {ev_float, "button14"},
2346 {ev_float, "button15"},
2347 {ev_float, "button16"},
2348 {ev_float, "buttonchat"},
2349 {ev_float, "buttonuse"},
2350 {ev_float, "clientcolors"},
2351 {ev_float, "cursor_active"},
2352 {ev_float, "fullbright"},
2353 {ev_float, "glow_color"},
2354 {ev_float, "glow_size"},
2355 {ev_float, "glow_trail"},
2356 {ev_float, "gravity"},
2357 {ev_float, "idealpitch"},
2358 {ev_float, "items2"},
2359 {ev_float, "light_lev"},
2360 {ev_float, "pflags"},
2362 {ev_float, "pitch_speed"},
2363 {ev_float, "pmodel"},
2364 {ev_float, "renderamt"}, // HalfLife support
2365 {ev_float, "rendermode"}, // HalfLife support
2366 {ev_float, "scale"},
2367 {ev_float, "style"},
2368 {ev_float, "tag_index"},
2369 {ev_float, "Version"},
2370 {ev_float, "viewzoom"},
2371 {ev_vector, "color"},
2372 {ev_vector, "colormod"},
2373 {ev_vector, "cursor_screen"},
2374 {ev_vector, "cursor_trace_endpos"},
2375 {ev_vector, "cursor_trace_start"},
2376 {ev_vector, "movement"},
2377 {ev_vector, "punchvector"},
2378 {ev_string, "playermodel"},
2379 {ev_string, "playerskin"},
2380 {ev_function, "SendEntity"},
2381 {ev_function, "customizeentityforclient"},
2384 void SV_VM_Setup(void)
2387 PRVM_InitProg( PRVM_SERVERPROG );
2389 // allocate the mempools
2390 prog->progs_mempool = Mem_AllocPool("Server Progs", 0, NULL);
2391 prog->builtins = vm_sv_builtins;
2392 prog->numbuiltins = vm_sv_numbuiltins;
2393 prog->headercrc = PROGHEADER_CRC;
2394 prog->max_edicts = 512;
2395 prog->limit_edicts = MAX_EDICTS;
2396 prog->reserved_edicts = svs.maxclients;
2397 prog->edictprivate_size = sizeof(edict_engineprivate_t);
2398 prog->name = "server";
2399 prog->extensionstring = vm_sv_extensions;
2400 prog->loadintoworld = true;
2402 prog->begin_increase_edicts = SV_VM_CB_BeginIncreaseEdicts;
2403 prog->end_increase_edicts = SV_VM_CB_EndIncreaseEdicts;
2404 prog->init_edict = SV_VM_CB_InitEdict;
2405 prog->free_edict = SV_VM_CB_FreeEdict;
2406 prog->count_edicts = SV_VM_CB_CountEdicts;
2407 prog->load_edict = SV_VM_CB_LoadEdict;
2408 prog->init_cmd = VM_SV_Cmd_Init;
2409 prog->reset_cmd = VM_SV_Cmd_Reset;
2410 prog->error_cmd = Host_Error;
2412 // TODO: add a requiredfuncs list (ask LH if this is necessary at all)
2413 PRVM_LoadProgs( sv_progs.string, 0, NULL, REQFIELDS, reqfields );
2414 SV_VM_FindEdictFieldOffsets();
2416 VM_AutoSentStats_Clear();//[515]: csqc
2417 EntityFrameCSQC_ClearVersions();//[515]: csqc
2422 void SV_VM_Begin(void)
2425 PRVM_SetProg( PRVM_SERVERPROG );
2427 *prog->time = (float) sv.time;
2430 void SV_VM_End(void)