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 if (client->netconnection)
412 client->netconnection->message.allowoverflow = true; // we can catch it
413 // updated by receiving "rate" command from client
414 client->rate = NET_MINRATE;
415 // no limits for local player
416 if (client->netconnection && LHNETADDRESS_GetAddressType(&client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP)
417 client->rate = 1000000000;
418 client->connecttime = realtime;
421 memcpy (client->spawn_parms, spawn_parms, sizeof(spawn_parms));
424 // call the progs to get default spawn parms for the new client
425 // set self to world to intentionally cause errors with broken SetNewParms code in some mods
426 prog->globals.server->self = 0;
427 PRVM_ExecuteProgram (prog->globals.server->SetNewParms, "QC function SetNewParms is missing");
428 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
429 client->spawn_parms[i] = (&prog->globals.server->parm1)[i];
432 // set up the entity for this client (including .colormap, .team, etc)
433 PRVM_ED_ClearEdict(client->edict);
435 // don't call SendServerinfo for a fresh botclient because its fields have
436 // not been set up by the qc yet
437 if (client->netconnection)
438 SV_SendServerinfo (client);
440 client->spawned = true;
445 ===============================================================================
449 ===============================================================================
458 void SV_ClearDatagram (void)
460 SZ_Clear (&sv.datagram);
464 =============================================================================
466 The PVS must include a small area around the client to allow head bobbing
467 or other small motion on the client side. Otherwise, a bob might cause an
468 entity that should be visible to not show up, especially when the bob
471 =============================================================================
474 int sv_writeentitiestoclient_pvsbytes;
475 unsigned char sv_writeentitiestoclient_pvs[MAX_MAP_LEAFS/8];
477 static int numsendentities;
478 static entity_state_t sendentities[MAX_EDICTS];
479 static entity_state_t *sendentitiesindex[MAX_EDICTS];
481 qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *cs, int e)
484 unsigned int modelindex, effects, flags, glowsize, lightstyle, lightpflags, light[4], specialvisibilityradius;
485 unsigned int customizeentityforclient;
487 vec3_t cullmins, cullmaxs;
491 // EF_NODRAW prevents sending for any reason except for your own
492 // client, so we must keep all clients in this superset
493 effects = (unsigned)ent->fields.server->effects;
495 // we can omit invisible entities with no effects that are not clients
496 // LordHavoc: this could kill tags attached to an invisible entity, I
497 // just hope we never have to support that case
498 i = (int)ent->fields.server->modelindex;
499 modelindex = (i >= 1 && i < MAX_MODELS && *PRVM_GetString(ent->fields.server->model)) ? i : 0;
502 i = (int)(PRVM_GETEDICTFIELDVALUE(ent, eval_glow_size)->_float * 0.25f);
503 glowsize = (unsigned char)bound(0, i, 255);
504 if (PRVM_GETEDICTFIELDVALUE(ent, eval_glow_trail)->_float)
505 flags |= RENDER_GLOWTRAIL;
507 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[0]*256;
508 light[0] = (unsigned short)bound(0, f, 65535);
509 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[1]*256;
510 light[1] = (unsigned short)bound(0, f, 65535);
511 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[2]*256;
512 light[2] = (unsigned short)bound(0, f, 65535);
513 f = PRVM_GETEDICTFIELDVALUE(ent, eval_light_lev)->_float;
514 light[3] = (unsigned short)bound(0, f, 65535);
515 lightstyle = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_style)->_float;
516 lightpflags = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_pflags)->_float;
518 if (gamemode == GAME_TENEBRAE)
520 // tenebrae's EF_FULLDYNAMIC conflicts with Q2's EF_NODRAW
524 lightpflags |= PFLAGS_FULLDYNAMIC;
526 // tenebrae's EF_GREEN conflicts with DP's EF_ADDITIVE
534 lightpflags |= PFLAGS_FULLDYNAMIC;
538 specialvisibilityradius = 0;
539 if (lightpflags & PFLAGS_FULLDYNAMIC)
540 specialvisibilityradius = max(specialvisibilityradius, light[3]);
542 specialvisibilityradius = max(specialvisibilityradius, glowsize * 4);
543 if (flags & RENDER_GLOWTRAIL)
544 specialvisibilityradius = max(specialvisibilityradius, 100);
545 if (effects & (EF_BRIGHTFIELD | EF_MUZZLEFLASH | EF_BRIGHTLIGHT | EF_DIMLIGHT | EF_RED | EF_BLUE | EF_FLAME | EF_STARDUST))
547 if (effects & EF_BRIGHTFIELD)
548 specialvisibilityradius = max(specialvisibilityradius, 80);
549 if (effects & EF_MUZZLEFLASH)
550 specialvisibilityradius = max(specialvisibilityradius, 100);
551 if (effects & EF_BRIGHTLIGHT)
552 specialvisibilityradius = max(specialvisibilityradius, 400);
553 if (effects & EF_DIMLIGHT)
554 specialvisibilityradius = max(specialvisibilityradius, 200);
555 if (effects & EF_RED)
556 specialvisibilityradius = max(specialvisibilityradius, 200);
557 if (effects & EF_BLUE)
558 specialvisibilityradius = max(specialvisibilityradius, 200);
559 if (effects & EF_FLAME)
560 specialvisibilityradius = max(specialvisibilityradius, 250);
561 if (effects & EF_STARDUST)
562 specialvisibilityradius = max(specialvisibilityradius, 100);
565 // early culling checks
566 // (final culling is done by SV_MarkWriteEntityStateToClient)
567 customizeentityforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_customizeentityforclient)->function;
568 if (!customizeentityforclient)
570 if (e > svs.maxclients && (!modelindex && !specialvisibilityradius))
572 // this 2 billion unit check is actually to detect NAN origins
573 // (we really don't want to send those)
574 if (VectorLength2(ent->fields.server->origin) > 2000000000.0*2000000000.0)
582 VectorCopy(ent->fields.server->origin, cs->origin);
583 VectorCopy(ent->fields.server->angles, cs->angles);
585 cs->effects = effects;
586 cs->colormap = (unsigned)ent->fields.server->colormap;
587 cs->modelindex = modelindex;
588 cs->skin = (unsigned)ent->fields.server->skin;
589 cs->frame = (unsigned)ent->fields.server->frame;
590 cs->viewmodelforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)->edict;
591 cs->exteriormodelforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_exteriormodeltoclient)->edict;
592 cs->nodrawtoclient = PRVM_GETEDICTFIELDVALUE(ent, eval_nodrawtoclient)->edict;
593 cs->drawonlytoclient = PRVM_GETEDICTFIELDVALUE(ent, eval_drawonlytoclient)->edict;
594 cs->customizeentityforclient = customizeentityforclient;
595 cs->tagentity = PRVM_GETEDICTFIELDVALUE(ent, eval_tag_entity)->edict;
596 cs->tagindex = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_tag_index)->_float;
597 cs->glowsize = glowsize;
599 // don't need to init cs->colormod because the defaultstate did that for us
600 //cs->colormod[0] = cs->colormod[1] = cs->colormod[2] = 32;
601 val = PRVM_GETEDICTFIELDVALUE(ent, eval_colormod);
602 if (val->vector[0] || val->vector[1] || val->vector[2])
604 i = val->vector[0] * 32.0f;cs->colormod[0] = bound(0, i, 255);
605 i = val->vector[1] * 32.0f;cs->colormod[1] = bound(0, i, 255);
606 i = val->vector[2] * 32.0f;cs->colormod[2] = bound(0, i, 255);
609 cs->modelindex = modelindex;
612 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_alpha)->_float * 255.0f);
616 cs->alpha = (unsigned char)bound(0, i, 255);
619 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_renderamt)->_float);
623 cs->alpha = (unsigned char)bound(0, i, 255);
627 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_scale)->_float * 16.0f);
631 cs->scale = (unsigned char)bound(0, i, 255);
635 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_glow_color)->_float);
637 cs->glowcolor = (int)f;
639 if (PRVM_GETEDICTFIELDVALUE(ent, eval_fullbright)->_float)
640 cs->effects |= EF_FULLBRIGHT;
642 if (ent->fields.server->movetype == MOVETYPE_STEP)
643 cs->flags |= RENDER_STEP;
644 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)
645 cs->flags |= RENDER_LOWPRECISION;
646 if (ent->fields.server->colormap >= 1024)
647 cs->flags |= RENDER_COLORMAPPED;
648 if (cs->viewmodelforclient)
649 cs->flags |= RENDER_VIEWMODEL; // show relative to the view
651 cs->light[0] = light[0];
652 cs->light[1] = light[1];
653 cs->light[2] = light[2];
654 cs->light[3] = light[3];
655 cs->lightstyle = lightstyle;
656 cs->lightpflags = lightpflags;
658 cs->specialvisibilityradius = specialvisibilityradius;
660 // calculate the visible box of this entity (don't use the physics box
661 // as that is often smaller than a model, and would not count
662 // specialvisibilityradius)
663 if ((model = sv.models[modelindex]))
665 float scale = cs->scale * (1.0f / 16.0f);
666 if (cs->angles[0] || cs->angles[2]) // pitch and roll
668 VectorMA(cs->origin, scale, model->rotatedmins, cullmins);
669 VectorMA(cs->origin, scale, model->rotatedmaxs, cullmaxs);
671 else if (cs->angles[1])
673 VectorMA(cs->origin, scale, model->yawmins, cullmins);
674 VectorMA(cs->origin, scale, model->yawmaxs, cullmaxs);
678 VectorMA(cs->origin, scale, model->normalmins, cullmins);
679 VectorMA(cs->origin, scale, model->normalmaxs, cullmaxs);
684 VectorCopy(cs->origin, cullmins);
685 VectorCopy(cs->origin, cullmaxs);
687 if (specialvisibilityradius)
689 cullmins[0] = min(cullmins[0], cs->origin[0] - specialvisibilityradius);
690 cullmins[1] = min(cullmins[1], cs->origin[1] - specialvisibilityradius);
691 cullmins[2] = min(cullmins[2], cs->origin[2] - specialvisibilityradius);
692 cullmaxs[0] = max(cullmaxs[0], cs->origin[0] + specialvisibilityradius);
693 cullmaxs[1] = max(cullmaxs[1], cs->origin[1] + specialvisibilityradius);
694 cullmaxs[2] = max(cullmaxs[2], cs->origin[2] + specialvisibilityradius);
696 if (!VectorCompare(cullmins, ent->priv.server->cullmins) || !VectorCompare(cullmaxs, ent->priv.server->cullmaxs))
698 VectorCopy(cullmins, ent->priv.server->cullmins);
699 VectorCopy(cullmaxs, ent->priv.server->cullmaxs);
700 ent->priv.server->pvs_numclusters = -1;
701 if (sv.worldmodel && sv.worldmodel->brush.FindBoxClusters)
703 i = sv.worldmodel->brush.FindBoxClusters(sv.worldmodel, cullmins, cullmaxs, MAX_ENTITYCLUSTERS, ent->priv.server->pvs_clusterlist);
704 if (i <= MAX_ENTITYCLUSTERS)
705 ent->priv.server->pvs_numclusters = i;
712 void SV_PrepareEntitiesForSending(void)
716 // send all entities that touch the pvs
718 sendentitiesindex[0] = NULL;
719 memset(sendentitiesindex, 0, prog->num_edicts * sizeof(entity_state_t *));
720 for (e = 1, ent = PRVM_NEXT_EDICT(prog->edicts);e < prog->num_edicts;e++, ent = PRVM_NEXT_EDICT(ent))
722 if (!ent->priv.server->free && SV_PrepareEntityForSending(ent, sendentities + numsendentities, e))
724 sendentitiesindex[e] = sendentities + numsendentities;
730 static int sententitiesmark = 0;
731 static int sententities[MAX_EDICTS];
732 static int sententitiesconsideration[MAX_EDICTS];
733 static int sv_writeentitiestoclient_culled_pvs;
734 static int sv_writeentitiestoclient_culled_trace;
735 static int sv_writeentitiestoclient_visibleentities;
736 static int sv_writeentitiestoclient_totalentities;
737 //static entity_frame_t sv_writeentitiestoclient_entityframe;
738 static int sv_writeentitiestoclient_clentnum;
739 static vec3_t sv_writeentitiestoclient_testeye;
740 static client_t *sv_writeentitiestoclient_client;
742 void SV_MarkWriteEntityStateToClient(entity_state_t *s)
749 if (sententitiesconsideration[s->number] == sententitiesmark)
751 sententitiesconsideration[s->number] = sententitiesmark;
752 sv_writeentitiestoclient_totalentities++;
754 if (s->customizeentityforclient)
756 prog->globals.server->self = s->number;
757 prog->globals.server->other = sv_writeentitiestoclient_clentnum;
758 PRVM_ExecuteProgram(s->customizeentityforclient, "customizeentityforclient: NULL function");
759 if(!PRVM_G_FLOAT(OFS_RETURN) || !SV_PrepareEntityForSending(PRVM_EDICT_NUM(s->number), s, s->number))
763 // never reject player
764 if (s->number != sv_writeentitiestoclient_clentnum)
766 // check various rejection conditions
767 if (s->nodrawtoclient == sv_writeentitiestoclient_clentnum)
769 if (s->drawonlytoclient && s->drawonlytoclient != sv_writeentitiestoclient_clentnum)
771 if (s->effects & EF_NODRAW)
773 // LordHavoc: only send entities with a model or important effects
774 if (!s->modelindex && s->specialvisibilityradius == 0)
777 // viewmodels don't have visibility checking
778 if (s->viewmodelforclient)
780 if (s->viewmodelforclient != sv_writeentitiestoclient_clentnum)
783 else if (s->tagentity)
785 // tag attached entities simply check their parent
786 if (!sendentitiesindex[s->tagentity])
788 SV_MarkWriteEntityStateToClient(sendentitiesindex[s->tagentity]);
789 if (sententities[s->tagentity] != sententitiesmark)
792 // always send world submodels in newer protocols because they don't
793 // generate much traffic (in old protocols they hog bandwidth)
794 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)))
796 // entity has survived every check so far, check if visible
797 ed = PRVM_EDICT_NUM(s->number);
799 // if not touching a visible leaf
800 if (sv_cullentities_pvs.integer && sv_writeentitiestoclient_pvsbytes)
802 if (ed->priv.server->pvs_numclusters < 0)
804 // entity too big for clusters list
805 if (sv.worldmodel && sv.worldmodel->brush.BoxTouchingPVS && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, sv_writeentitiestoclient_pvs, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
807 sv_writeentitiestoclient_culled_pvs++;
814 // check cached clusters list
815 for (i = 0;i < ed->priv.server->pvs_numclusters;i++)
816 if (CHECKPVSBIT(sv_writeentitiestoclient_pvs, ed->priv.server->pvs_clusterlist[i]))
818 if (i == ed->priv.server->pvs_numclusters)
820 sv_writeentitiestoclient_culled_pvs++;
826 // or not seen by random tracelines
827 if (sv_cullentities_trace.integer && !isbmodel)
829 // LordHavoc: test center first
830 testorigin[0] = (ed->priv.server->cullmins[0] + ed->priv.server->cullmaxs[0]) * 0.5f;
831 testorigin[1] = (ed->priv.server->cullmins[1] + ed->priv.server->cullmaxs[1]) * 0.5f;
832 testorigin[2] = (ed->priv.server->cullmins[2] + ed->priv.server->cullmaxs[2]) * 0.5f;
833 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, sv_writeentitiestoclient_testeye, testorigin, testorigin, SUPERCONTENTS_SOLID);
834 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
835 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
838 // LordHavoc: test random offsets, to maximize chance of detection
839 testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]);
840 testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]);
841 testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]);
842 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, sv_writeentitiestoclient_testeye, testorigin, testorigin, SUPERCONTENTS_SOLID);
843 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
844 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
847 if (s->specialvisibilityradius)
849 // LordHavoc: test random offsets, to maximize chance of detection
850 testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]);
851 testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]);
852 testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]);
853 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, sv_writeentitiestoclient_testeye, testorigin, testorigin, SUPERCONTENTS_SOLID);
854 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
855 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
859 if (realtime > sv_writeentitiestoclient_client->visibletime[s->number])
861 sv_writeentitiestoclient_culled_trace++;
868 // this just marks it for sending
869 // FIXME: it would be more efficient to send here, but the entity
870 // compressor isn't that flexible
871 sv_writeentitiestoclient_visibleentities++;
872 sententities[s->number] = sententitiesmark;
875 entity_state_t sendstates[MAX_EDICTS];
876 extern int csqc_clent;
878 void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t *msg, int *stats)
880 int i, numsendstates;
883 // if there isn't enough space to accomplish anything, skip it
884 if (msg->cursize + 25 > msg->maxsize)
887 sv_writeentitiestoclient_client = client;
889 sv_writeentitiestoclient_culled_pvs = 0;
890 sv_writeentitiestoclient_culled_trace = 0;
891 sv_writeentitiestoclient_visibleentities = 0;
892 sv_writeentitiestoclient_totalentities = 0;
894 // find the client's PVS
895 // the real place being tested from
896 VectorAdd(clent->fields.server->origin, clent->fields.server->view_ofs, sv_writeentitiestoclient_testeye);
897 sv_writeentitiestoclient_pvsbytes = 0;
898 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
899 sv_writeentitiestoclient_pvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, sv_writeentitiestoclient_testeye, 8, sv_writeentitiestoclient_pvs, sizeof(sv_writeentitiestoclient_pvs));
901 csqc_clent = sv_writeentitiestoclient_clentnum = PRVM_EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes
905 for (i = 0;i < numsendentities;i++)
906 SV_MarkWriteEntityStateToClient(sendentities + i);
909 for (i = 0;i < numsendentities;i++)
911 if (sententities[sendentities[i].number] == sententitiesmark)
913 s = &sendstates[numsendstates++];
914 *s = sendentities[i];
915 if (s->exteriormodelforclient && s->exteriormodelforclient == sv_writeentitiestoclient_clentnum)
916 s->flags |= RENDER_EXTERIORMODEL;
920 if (sv_cullentities_stats.integer)
921 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);
923 EntityFrameCSQC_WriteFrame(msg, numsendstates, sendstates);
925 if (client->entitydatabase5)
926 EntityFrame5_WriteFrame(msg, client->entitydatabase5, numsendstates, sendstates, client - svs.clients + 1, stats, client->movesequence);
927 else if (client->entitydatabase4)
928 EntityFrame4_WriteFrame(msg, client->entitydatabase4, numsendstates, sendstates);
929 else if (client->entitydatabase)
930 EntityFrame_WriteFrame(msg, client->entitydatabase, numsendstates, sendstates, client - svs.clients + 1);
932 EntityFrameQuake_WriteFrame(msg, numsendstates, sendstates);
941 void SV_CleanupEnts (void)
946 ent = PRVM_NEXT_EDICT(prog->edicts);
947 for (e=1 ; e<prog->num_edicts ; e++, ent = PRVM_NEXT_EDICT(ent))
948 ent->fields.server->effects = (int)ent->fields.server->effects & ~EF_MUZZLEFLASH;
953 SV_WriteClientdataToMessage
957 void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
965 unsigned char viewzoom;
969 // send a damage message
971 if (ent->fields.server->dmg_take || ent->fields.server->dmg_save)
973 other = PRVM_PROG_TO_EDICT(ent->fields.server->dmg_inflictor);
974 MSG_WriteByte (msg, svc_damage);
975 MSG_WriteByte (msg, ent->fields.server->dmg_save);
976 MSG_WriteByte (msg, ent->fields.server->dmg_take);
977 for (i=0 ; i<3 ; i++)
978 MSG_WriteCoord (msg, other->fields.server->origin[i] + 0.5*(other->fields.server->mins[i] + other->fields.server->maxs[i]), sv.protocol);
980 ent->fields.server->dmg_take = 0;
981 ent->fields.server->dmg_save = 0;
985 // send the current viewpos offset from the view entity
987 SV_SetIdealPitch (); // how much to look up / down ideally
989 // a fixangle might get lost in a dropped packet. Oh well.
990 if ( ent->fields.server->fixangle )
992 MSG_WriteByte (msg, svc_setangle);
993 for (i=0 ; i < 3 ; i++)
994 MSG_WriteAngle (msg, ent->fields.server->angles[i], sv.protocol);
995 ent->fields.server->fixangle = 0;
998 // stuff the sigil bits into the high bits of items for sbar, or else
1000 val = PRVM_GETEDICTFIELDVALUE(ent, eval_items2);
1001 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
1002 items = (int)ent->fields.server->items | ((int)val->_float << 23);
1004 items = (int)ent->fields.server->items | ((int)prog->globals.server->serverflags << 28);
1006 VectorClear(punchvector);
1007 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_punchvector)))
1008 VectorCopy(val->vector, punchvector);
1010 // cache weapon model name and index in client struct to save time
1011 // (this search can be almost 1% of cpu time!)
1012 s = PRVM_GetString(ent->fields.server->weaponmodel);
1013 if (strcmp(s, client->weaponmodel))
1015 strlcpy(client->weaponmodel, s, sizeof(client->weaponmodel));
1016 client->weaponmodelindex = SV_ModelIndex(s, 1);
1020 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_viewzoom)))
1021 viewzoom = val->_float * 255.0f;
1027 if ((int)ent->fields.server->flags & FL_ONGROUND)
1028 bits |= SU_ONGROUND;
1029 if (ent->fields.server->waterlevel >= 2)
1031 if (ent->fields.server->idealpitch)
1032 bits |= SU_IDEALPITCH;
1034 for (i=0 ; i<3 ; i++)
1036 if (ent->fields.server->punchangle[i])
1037 bits |= (SU_PUNCH1<<i);
1038 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
1040 bits |= (SU_PUNCHVEC1<<i);
1041 if (ent->fields.server->velocity[i])
1042 bits |= (SU_VELOCITY1<<i);
1045 memset(stats, 0, sizeof(int[MAX_CL_STATS]));
1046 stats[STAT_VIEWHEIGHT] = ent->fields.server->view_ofs[2];
1047 stats[STAT_ITEMS] = items;
1048 stats[STAT_WEAPONFRAME] = ent->fields.server->weaponframe;
1049 stats[STAT_ARMOR] = ent->fields.server->armorvalue;
1050 stats[STAT_WEAPON] = client->weaponmodelindex;
1051 stats[STAT_HEALTH] = ent->fields.server->health;
1052 stats[STAT_AMMO] = ent->fields.server->currentammo;
1053 stats[STAT_SHELLS] = ent->fields.server->ammo_shells;
1054 stats[STAT_NAILS] = ent->fields.server->ammo_nails;
1055 stats[STAT_ROCKETS] = ent->fields.server->ammo_rockets;
1056 stats[STAT_CELLS] = ent->fields.server->ammo_cells;
1057 stats[STAT_ACTIVEWEAPON] = ent->fields.server->weapon;
1058 stats[STAT_VIEWZOOM] = viewzoom;
1059 // the QC bumps these itself by sending svc_'s, so we have to keep them
1060 // zero or they'll be corrected by the engine
1061 //stats[STAT_TOTALSECRETS] = prog->globals.server->total_secrets;
1062 //stats[STAT_TOTALMONSTERS] = prog->globals.server->total_monsters;
1063 //stats[STAT_SECRETS] = prog->globals.server->found_secrets;
1064 //stats[STAT_MONSTERS] = prog->globals.server->killed_monsters;
1066 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)
1068 if (stats[STAT_VIEWHEIGHT] != DEFAULT_VIEWHEIGHT) bits |= SU_VIEWHEIGHT;
1070 if (stats[STAT_WEAPONFRAME]) bits |= SU_WEAPONFRAME;
1071 if (stats[STAT_ARMOR]) bits |= SU_ARMOR;
1073 // FIXME: which protocols support this? does PROTOCOL_DARKPLACES3 support viewzoom?
1074 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
1075 if (viewzoom != 255)
1076 bits |= SU_VIEWZOOM;
1081 if (bits >= 16777216)
1085 MSG_WriteByte (msg, svc_clientdata);
1086 MSG_WriteShort (msg, bits);
1087 if (bits & SU_EXTEND1)
1088 MSG_WriteByte(msg, bits >> 16);
1089 if (bits & SU_EXTEND2)
1090 MSG_WriteByte(msg, bits >> 24);
1092 if (bits & SU_VIEWHEIGHT)
1093 MSG_WriteChar (msg, stats[STAT_VIEWHEIGHT]);
1095 if (bits & SU_IDEALPITCH)
1096 MSG_WriteChar (msg, ent->fields.server->idealpitch);
1098 for (i=0 ; i<3 ; i++)
1100 if (bits & (SU_PUNCH1<<i))
1102 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1103 MSG_WriteChar(msg, ent->fields.server->punchangle[i]);
1105 MSG_WriteAngle16i(msg, ent->fields.server->punchangle[i]);
1107 if (bits & (SU_PUNCHVEC1<<i))
1109 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1110 MSG_WriteCoord16i(msg, punchvector[i]);
1112 MSG_WriteCoord32f(msg, punchvector[i]);
1114 if (bits & (SU_VELOCITY1<<i))
1116 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1117 MSG_WriteChar(msg, ent->fields.server->velocity[i] * (1.0f / 16.0f));
1119 MSG_WriteCoord32f(msg, ent->fields.server->velocity[i]);
1123 if (bits & SU_ITEMS)
1124 MSG_WriteLong (msg, stats[STAT_ITEMS]);
1126 if (sv.protocol == PROTOCOL_DARKPLACES5)
1128 if (bits & SU_WEAPONFRAME)
1129 MSG_WriteShort (msg, stats[STAT_WEAPONFRAME]);
1130 if (bits & SU_ARMOR)
1131 MSG_WriteShort (msg, stats[STAT_ARMOR]);
1132 if (bits & SU_WEAPON)
1133 MSG_WriteShort (msg, stats[STAT_WEAPON]);
1134 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1135 MSG_WriteShort (msg, stats[STAT_AMMO]);
1136 MSG_WriteShort (msg, stats[STAT_SHELLS]);
1137 MSG_WriteShort (msg, stats[STAT_NAILS]);
1138 MSG_WriteShort (msg, stats[STAT_ROCKETS]);
1139 MSG_WriteShort (msg, stats[STAT_CELLS]);
1140 MSG_WriteShort (msg, stats[STAT_ACTIVEWEAPON]);
1141 if (bits & SU_VIEWZOOM)
1142 MSG_WriteShort (msg, min(stats[STAT_VIEWZOOM], 65535));
1144 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)
1146 if (bits & SU_WEAPONFRAME)
1147 MSG_WriteByte (msg, stats[STAT_WEAPONFRAME]);
1148 if (bits & SU_ARMOR)
1149 MSG_WriteByte (msg, stats[STAT_ARMOR]);
1150 if (bits & SU_WEAPON)
1151 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1152 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1153 MSG_WriteByte (msg, stats[STAT_AMMO]);
1154 MSG_WriteByte (msg, stats[STAT_SHELLS]);
1155 MSG_WriteByte (msg, stats[STAT_NAILS]);
1156 MSG_WriteByte (msg, stats[STAT_ROCKETS]);
1157 MSG_WriteByte (msg, stats[STAT_CELLS]);
1158 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_NEXUIZ)
1160 for (i = 0;i < 32;i++)
1161 if (stats[STAT_WEAPON] & (1<<i))
1163 MSG_WriteByte (msg, i);
1166 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1167 if (bits & SU_VIEWZOOM)
1169 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1170 MSG_WriteByte (msg, min(stats[STAT_VIEWZOOM], 255));
1172 MSG_WriteShort (msg, min(stats[STAT_VIEWZOOM], 65535));
1178 =======================
1179 SV_SendClientDatagram
1180 =======================
1182 static unsigned char sv_sendclientdatagram_buf[NET_MAXMESSAGE]; // FIXME?
1183 qboolean SV_SendClientDatagram (client_t *client)
1185 int rate, maxrate, maxsize, maxsize2;
1187 int stats[MAX_CL_STATS];
1189 if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP && !sv_ratelimitlocalplayer.integer)
1191 // for good singleplayer, send huge packets
1192 maxsize = sizeof(sv_sendclientdatagram_buf);
1193 maxsize2 = sizeof(sv_sendclientdatagram_buf);
1195 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)
1197 // no rate limiting support on older protocols because dp protocols
1198 // 1-4 kick the client off if they overflow, and quake protocol shows
1199 // less than the full entity set if rate limited
1205 // PROTOCOL_DARKPLACES5 and later support packet size limiting of updates
1206 maxrate = bound(NET_MINRATE, sv_maxrate.integer, NET_MAXRATE);
1207 if (sv_maxrate.integer != maxrate)
1208 Cvar_SetValueQuick(&sv_maxrate, maxrate);
1210 // this rate limiting does not understand sys_ticrate 0
1211 // (but no one should be running that on a server!)
1212 rate = bound(NET_MINRATE, client->rate, maxrate);
1213 rate = (int)(client->rate * sys_ticrate.value);
1214 maxsize = bound(100, rate, 1400);
1218 msg.data = sv_sendclientdatagram_buf;
1219 msg.maxsize = maxsize;
1222 MSG_WriteByte (&msg, svc_time);
1223 MSG_WriteFloat (&msg, sv.time);
1225 // add the client specific data to the datagram
1226 SV_WriteClientdataToMessage (client, client->edict, &msg, stats);
1227 VM_SV_WriteAutoSentStats (client, client->edict, &msg, stats);
1228 SV_WriteEntitiesToClient (client, client->edict, &msg, stats);
1230 // expand packet size to allow effects to go over the rate limit
1231 // (dropping them is FAR too ugly)
1232 msg.maxsize = maxsize2;
1234 // copy the server datagram if there is space
1235 // FIXME: put in delayed queue of effects to send
1236 if (sv.datagram.cursize > 0 && msg.cursize + sv.datagram.cursize <= msg.maxsize)
1237 SZ_Write (&msg, sv.datagram.data, sv.datagram.cursize);
1239 // send the datagram
1240 if (NetConn_SendUnreliableMessage (client->netconnection, &msg) == -1)
1242 SV_DropClient (true);// if the message couldn't send, kick off
1250 =======================
1251 SV_UpdateToReliableMessages
1252 =======================
1254 void SV_UpdateToReliableMessages (void)
1263 // check for changes to be sent over the reliable streams
1264 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1266 // update the host_client fields we care about according to the entity fields
1267 host_client->edict = PRVM_EDICT_NUM(i+1);
1270 name = PRVM_GetString(host_client->edict->fields.server->netname);
1273 // always point the string back at host_client->name to keep it safe
1274 strlcpy (host_client->name, name, sizeof (host_client->name));
1275 host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
1276 if (strcmp(host_client->old_name, host_client->name))
1278 if (host_client->spawned)
1279 SV_BroadcastPrintf("%s changed name to %s\n", host_client->old_name, host_client->name);
1280 strcpy(host_client->old_name, host_client->name);
1281 // send notification to all clients
1282 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
1283 MSG_WriteByte (&sv.reliable_datagram, i);
1284 MSG_WriteString (&sv.reliable_datagram, host_client->name);
1287 // DP_SV_CLIENTCOLORS
1288 // this is always found (since it's added by the progs loader)
1289 if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_clientcolors)))
1290 host_client->colors = (int)val->_float;
1291 if (host_client->old_colors != host_client->colors)
1293 host_client->old_colors = host_client->colors;
1294 // send notification to all clients
1295 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1296 MSG_WriteByte (&sv.reliable_datagram, i);
1297 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1300 // NEXUIZ_PLAYERMODEL
1301 if( eval_playermodel ) {
1302 model = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string);
1305 // always point the string back at host_client->name to keep it safe
1306 strlcpy (host_client->playermodel, model, sizeof (host_client->playermodel));
1307 PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
1310 // NEXUIZ_PLAYERSKIN
1311 if( eval_playerskin ) {
1312 skin = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string);
1315 // always point the string back at host_client->name to keep it safe
1316 strlcpy (host_client->playerskin, skin, sizeof (host_client->playerskin));
1317 PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
1321 host_client->frags = (int)host_client->edict->fields.server->frags;
1322 if (host_client->old_frags != host_client->frags)
1324 host_client->old_frags = host_client->frags;
1325 // send notification to all clients
1326 MSG_WriteByte (&sv.reliable_datagram, svc_updatefrags);
1327 MSG_WriteByte (&sv.reliable_datagram, i);
1328 MSG_WriteShort (&sv.reliable_datagram, host_client->frags);
1332 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1333 if (client->netconnection)
1334 SZ_Write (&client->netconnection->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
1336 SZ_Clear (&sv.reliable_datagram);
1341 =======================
1344 Send a nop message without trashing or sending the accumulated client
1346 =======================
1348 void SV_SendNop (client_t *client)
1351 unsigned char buf[4];
1354 msg.maxsize = sizeof(buf);
1357 MSG_WriteChar (&msg, svc_nop);
1359 if (NetConn_SendUnreliableMessage (client->netconnection, &msg) == -1)
1360 SV_DropClient (true); // if the message couldn't send, kick off
1361 client->last_message = realtime;
1365 =======================
1366 SV_SendClientMessages
1367 =======================
1369 void SV_SendClientMessages (void)
1371 int i, prepared = false;
1373 // update frags, names, etc
1374 SV_UpdateToReliableMessages();
1376 // build individual updates
1377 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1379 if (!host_client->active)
1381 if (!host_client->netconnection)
1384 if (host_client->netconnection->message.overflowed)
1386 SV_DropClient (true); // if the message couldn't send, kick off
1390 if (host_client->spawned)
1395 // only prepare entities once per frame
1396 SV_PrepareEntitiesForSending();
1398 if (!SV_SendClientDatagram (host_client))
1403 // the player isn't totally in the game yet
1404 // send small keepalive messages if too much time has passed
1405 // send a full message when the next signon stage has been requested
1406 // some other message data (name changes, etc) may accumulate
1407 // between signon stages
1408 if (!host_client->sendsignon)
1410 if (realtime - host_client->last_message > 5)
1411 SV_SendNop (host_client);
1412 continue; // don't send out non-signon messages
1416 if (host_client->netconnection->message.cursize)
1418 if (!NetConn_CanSendMessage (host_client->netconnection))
1421 if (NetConn_SendReliableMessage (host_client->netconnection, &host_client->netconnection->message) == -1)
1422 SV_DropClient (true); // if the message couldn't send, kick off
1423 SZ_Clear (&host_client->netconnection->message);
1424 host_client->last_message = realtime;
1425 host_client->sendsignon = false;
1429 // clear muzzle flashes
1435 ==============================================================================
1439 ==============================================================================
1448 int SV_ModelIndex(const char *s, int precachemode)
1450 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_MODELS);
1451 char filename[MAX_QPATH];
1455 //if (precachemode == 2)
1457 strlcpy(filename, s, sizeof(filename));
1458 for (i = 2;i < limit;i++)
1460 if (!sv.model_precache[i][0])
1464 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))
1466 Con_Printf("SV_ModelIndex(\"%s\"): precache_model can only be done in spawn functions\n", filename);
1469 if (precachemode == 1)
1470 Con_Printf("SV_ModelIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1471 strlcpy(sv.model_precache[i], filename, sizeof(sv.model_precache[i]));
1472 sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, false);
1473 if (sv.state != ss_loading)
1475 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1476 MSG_WriteShort(&sv.reliable_datagram, i);
1477 MSG_WriteString(&sv.reliable_datagram, filename);
1481 Con_Printf("SV_ModelIndex(\"%s\"): not precached\n", filename);
1484 if (!strcmp(sv.model_precache[i], filename))
1487 Con_Printf("SV_ModelIndex(\"%s\"): i (%i) == MAX_MODELS (%i)\n", filename, i, MAX_MODELS);
1497 int SV_SoundIndex(const char *s, int precachemode)
1499 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_SOUNDS);
1500 char filename[MAX_QPATH];
1504 //if (precachemode == 2)
1506 strlcpy(filename, s, sizeof(filename));
1507 for (i = 1;i < limit;i++)
1509 if (!sv.sound_precache[i][0])
1513 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))
1515 Con_Printf("SV_SoundIndex(\"%s\"): precache_sound can only be done in spawn functions\n", filename);
1518 if (precachemode == 1)
1519 Con_Printf("SV_SoundIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1520 strlcpy(sv.sound_precache[i], filename, sizeof(sv.sound_precache[i]));
1521 if (sv.state != ss_loading)
1523 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1524 MSG_WriteShort(&sv.reliable_datagram, i + 32768);
1525 MSG_WriteString(&sv.reliable_datagram, filename);
1529 Con_Printf("SV_SoundIndex(\"%s\"): not precached\n", filename);
1532 if (!strcmp(sv.sound_precache[i], filename))
1535 Con_Printf("SV_SoundIndex(\"%s\"): i (%i) == MAX_SOUNDS (%i)\n", filename, i, MAX_SOUNDS);
1545 void SV_CreateBaseline (void)
1547 int i, entnum, large;
1548 prvm_edict_t *svent;
1550 // LordHavoc: clear *all* states (note just active ones)
1551 for (entnum = 0;entnum < prog->max_edicts;entnum++)
1553 // get the current server version
1554 svent = PRVM_EDICT_NUM(entnum);
1556 // LordHavoc: always clear state values, whether the entity is in use or not
1557 svent->priv.server->baseline = defaultstate;
1559 if (svent->priv.server->free)
1561 if (entnum > svs.maxclients && !svent->fields.server->modelindex)
1564 // create entity baseline
1565 VectorCopy (svent->fields.server->origin, svent->priv.server->baseline.origin);
1566 VectorCopy (svent->fields.server->angles, svent->priv.server->baseline.angles);
1567 svent->priv.server->baseline.frame = svent->fields.server->frame;
1568 svent->priv.server->baseline.skin = svent->fields.server->skin;
1569 if (entnum > 0 && entnum <= svs.maxclients)
1571 svent->priv.server->baseline.colormap = entnum;
1572 svent->priv.server->baseline.modelindex = SV_ModelIndex("progs/player.mdl", 1);
1576 svent->priv.server->baseline.colormap = 0;
1577 svent->priv.server->baseline.modelindex = svent->fields.server->modelindex;
1581 if (svent->priv.server->baseline.modelindex & 0xFF00 || svent->priv.server->baseline.frame & 0xFF00)
1584 // add to the message
1586 MSG_WriteByte (&sv.signon, svc_spawnbaseline2);
1588 MSG_WriteByte (&sv.signon, svc_spawnbaseline);
1589 MSG_WriteShort (&sv.signon, entnum);
1593 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.modelindex);
1594 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.frame);
1598 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.modelindex);
1599 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.frame);
1601 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.colormap);
1602 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.skin);
1603 for (i=0 ; i<3 ; i++)
1605 MSG_WriteCoord(&sv.signon, svent->priv.server->baseline.origin[i], sv.protocol);
1606 MSG_WriteAngle(&sv.signon, svent->priv.server->baseline.angles[i], sv.protocol);
1616 Grabs the current state of each client for saving across the
1617 transition to another level
1620 void SV_SaveSpawnparms (void)
1624 svs.serverflags = prog->globals.server->serverflags;
1626 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1628 if (!host_client->active)
1631 // call the progs to get default spawn parms for the new client
1632 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1633 PRVM_ExecuteProgram (prog->globals.server->SetChangeParms, "QC function SetChangeParms is missing");
1634 for (j=0 ; j<NUM_SPAWN_PARMS ; j++)
1635 host_client->spawn_parms[j] = (&prog->globals.server->parm1)[j];
1639 void SV_IncreaseEdicts(void)
1643 int oldmax_edicts = prog->max_edicts;
1644 void *oldedictsengineprivate = prog->edictprivate;
1645 void *oldedictsfields = prog->edictsfields;
1646 void *oldmoved_edicts = sv.moved_edicts;
1648 if (prog->max_edicts >= MAX_EDICTS)
1651 // links don't survive the transition, so unlink everything
1652 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1654 if (!ent->priv.server->free)
1655 SV_UnlinkEdict(prog->edicts + i);
1656 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
1660 prog->max_edicts = min(prog->max_edicts + 256, MAX_EDICTS);
1661 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
1662 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);
1663 sv.moved_edicts = PR_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1665 memcpy(prog->edictprivate, oldedictsengineprivate, oldmax_edicts * sizeof(edict_engineprivate_t));
1666 memcpy(prog->edictsfields, oldedictsfields, oldmax_edicts * prog->edict_size);
1668 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1670 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
1671 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
1672 // link every entity except world
1673 if (!ent->priv.server->free)
1674 SV_LinkEdict(ent, false);
1677 PR_Free(oldedictsengineprivate);
1678 PR_Free(oldedictsfields);
1679 PR_Free(oldmoved_edicts);
1686 This is called at the start of each level
1689 extern float scr_centertime_off;
1691 void SV_SpawnServer (const char *server)
1696 model_t *worldmodel;
1697 char modelname[sizeof(sv.modelname)];
1699 Con_DPrintf("SpawnServer: %s\n", server);
1701 if (cls.state != ca_dedicated)
1702 SCR_BeginLoadingPlaque();
1704 dpsnprintf (modelname, sizeof(modelname), "maps/%s.bsp", server);
1705 worldmodel = Mod_ForName(modelname, false, true, true);
1706 if (!worldmodel || !worldmodel->TraceBox)
1708 Con_Printf("Couldn't load map %s\n", modelname);
1712 // let's not have any servers with no name
1713 if (hostname.string[0] == 0)
1714 Cvar_Set ("hostname", "UNNAMED");
1715 scr_centertime_off = 0;
1717 svs.changelevel_issued = false; // now safe to issue another
1720 // tell all connected clients that we are going to a new level
1724 // Tell all the clients that the server is changing levels
1726 MSG_WriteByte(&sv.reliable_datagram, svc_stufftext);
1727 MSG_WriteString(&sv.reliable_datagram, "reconnect\n");
1733 NetConn_OpenServerPorts(true);
1737 // make cvars consistant
1740 Cvar_SetValue ("deathmatch", 0);
1741 // LordHavoc: it can be useful to have skills outside the range 0-3...
1742 //current_skill = bound(0, (int)(skill.value + 0.5), 3);
1743 //Cvar_SetValue ("skill", (float)current_skill);
1744 current_skill = (int)(skill.value + 0.5);
1747 // set up the new server
1749 Host_ClearMemory ();
1751 memset (&sv, 0, sizeof(sv));
1757 strlcpy (sv.name, server, sizeof (sv.name));
1759 sv.protocol = Protocol_EnumForName(sv_protocolname.string);
1760 if (sv.protocol == PROTOCOL_UNKNOWN)
1763 Protocol_Names(buffer, sizeof(buffer));
1764 Con_Printf("Unknown sv_protocolname \"%s\", valid values are:\n%s\n", sv_protocolname.string, buffer);
1765 sv.protocol = PROTOCOL_QUAKE;
1770 // load progs to get entity field count
1771 //PR_LoadProgs ( sv_progs.string );
1773 // allocate server memory
1774 /*// start out with just enough room for clients and a reasonable estimate of entities
1775 prog->max_edicts = max(svs.maxclients + 1, 512);
1776 prog->max_edicts = min(prog->max_edicts, MAX_EDICTS);
1778 // prvm_edict_t structures (hidden from progs)
1779 prog->edicts = PR_Alloc(MAX_EDICTS * sizeof(prvm_edict_t));
1780 // engine private structures (hidden from progs)
1781 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
1782 // progs fields, often accessed by server
1783 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);*/
1784 // used by PushMove to move back pushed entities
1785 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1786 /*for (i = 0;i < prog->max_edicts;i++)
1788 ent = prog->edicts + i;
1789 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
1790 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
1793 // reset client csqc entity versions right away.
1794 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1795 EntityFrameCSQC_InitClientVersions(i, true);
1797 sv.datagram.maxsize = sizeof(sv.datagram_buf);
1798 sv.datagram.cursize = 0;
1799 sv.datagram.data = sv.datagram_buf;
1801 sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf);
1802 sv.reliable_datagram.cursize = 0;
1803 sv.reliable_datagram.data = sv.reliable_datagram_buf;
1805 sv.signon.maxsize = sizeof(sv.signon_buf);
1806 sv.signon.cursize = 0;
1807 sv.signon.data = sv.signon_buf;
1809 // leave slots at start for clients only
1810 //prog->num_edicts = svs.maxclients+1;
1812 sv.state = ss_loading;
1813 prog->allowworldwrites = true;
1816 *prog->time = sv.time = 1.0;
1819 worldmodel->used = true;
1821 strlcpy (sv.name, server, sizeof (sv.name));
1822 strcpy(sv.modelname, modelname);
1823 sv.worldmodel = worldmodel;
1824 sv.models[1] = sv.worldmodel;
1827 // clear world interaction links
1831 strlcpy(sv.sound_precache[0], "", sizeof(sv.sound_precache[0]));
1833 strlcpy(sv.model_precache[0], "", sizeof(sv.model_precache[0]));
1834 strlcpy(sv.model_precache[1], sv.modelname, sizeof(sv.model_precache[1]));
1835 for (i = 1;i < sv.worldmodel->brush.numsubmodels;i++)
1837 dpsnprintf(sv.model_precache[i+1], sizeof(sv.model_precache[i+1]), "*%i", i);
1838 sv.models[i+1] = Mod_ForName (sv.model_precache[i+1], false, false, false);
1842 // load the rest of the entities
1844 // AK possible hack since num_edicts is still 0
1845 ent = PRVM_EDICT_NUM(0);
1846 memset (ent->fields.server, 0, prog->progs->entityfields * 4);
1847 ent->priv.server->free = false;
1848 ent->fields.server->model = PRVM_SetEngineString(sv.modelname);
1849 ent->fields.server->modelindex = 1; // world model
1850 ent->fields.server->solid = SOLID_BSP;
1851 ent->fields.server->movetype = MOVETYPE_PUSH;
1854 prog->globals.server->coop = coop.integer;
1856 prog->globals.server->deathmatch = deathmatch.integer;
1858 prog->globals.server->mapname = PRVM_SetEngineString(sv.name);
1860 // serverflags are for cross level information (sigils)
1861 prog->globals.server->serverflags = svs.serverflags;
1863 // we need to reset the spawned flag on all connected clients here so that
1864 // their thinks don't run during startup (before PutClientInServer)
1865 // we also need to set up the client entities now
1866 // and we need to set the ->edict pointers to point into the progs edicts
1867 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1869 host_client->spawned = false;
1870 host_client->edict = PRVM_EDICT_NUM(i + 1);
1871 PRVM_ED_ClearEdict(host_client->edict);
1874 // load replacement entity file if found
1876 if (sv_entpatch.integer)
1877 entities = (char *)FS_LoadFile(va("maps/%s.ent", sv.name), tempmempool, true, NULL);
1880 Con_Printf("Loaded maps/%s.ent\n", sv.name);
1881 PRVM_ED_LoadFromFile (entities);
1885 PRVM_ED_LoadFromFile (sv.worldmodel->brush.entities);
1888 // LordHavoc: clear world angles (to fix e3m3.bsp)
1889 VectorClear(prog->edicts->fields.server->angles);
1891 // all setup is completed, any further precache statements are errors
1892 sv.state = ss_active;
1893 prog->allowworldwrites = false;
1895 // run two frames to allow everything to settle
1896 for (i = 0;i < 2;i++)
1898 sv.frametime = host_frametime = 0.1;
1904 // create a baseline for more efficient communications
1905 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1906 SV_CreateBaseline ();
1908 // send serverinfo to all connected clients, and set up botclients coming back from a level change
1909 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1911 if (!host_client->active)
1913 if (host_client->netconnection)
1914 SV_SendServerinfo(host_client);
1918 // if client is a botclient coming from a level change, we need to
1919 // set up client info that normally requires networking
1921 // copy spawn parms out of the client_t
1922 for (j=0 ; j< NUM_SPAWN_PARMS ; j++)
1923 (&prog->globals.server->parm1)[j] = host_client->spawn_parms[j];
1925 // call the spawn function
1926 host_client->clientconnectcalled = true;
1927 prog->globals.server->time = sv.time;
1928 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1929 PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
1930 PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
1931 host_client->spawned = true;
1935 Con_DPrint("Server spawned.\n");
1936 NetConn_Heartbeat (2);
1941 /////////////////////////////////////////////////////
1944 void SV_VM_CB_BeginIncreaseEdicts(void)
1949 PRVM_Free( sv.moved_edicts );
1950 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1952 // links don't survive the transition, so unlink everything
1953 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1955 if (!ent->priv.server->free)
1956 SV_UnlinkEdict(prog->edicts + i);
1957 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
1962 void SV_VM_CB_EndIncreaseEdicts(void)
1967 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1969 // link every entity except world
1970 if (!ent->priv.server->free)
1971 SV_LinkEdict(ent, false);
1975 void SV_VM_CB_InitEdict(prvm_edict_t *e)
1977 // LordHavoc: for consistency set these here
1978 int num = PRVM_NUM_FOR_EDICT(e) - 1;
1980 if (num >= 0 && num < svs.maxclients)
1983 // set colormap and team on newly created player entity
1984 e->fields.server->colormap = num + 1;
1985 e->fields.server->team = (svs.clients[num].colors & 15) + 1;
1986 // set netname/clientcolors back to client values so that
1987 // DP_SV_CLIENTNAME and DP_SV_CLIENTCOLORS will not immediately
1989 e->fields.server->netname = PRVM_SetEngineString(svs.clients[num].name);
1990 if ((val = PRVM_GETEDICTFIELDVALUE(e, eval_clientcolors)))
1991 val->_float = svs.clients[num].colors;
1992 // NEXUIZ_PLAYERMODEL and NEXUIZ_PLAYERSKIN
1993 if( eval_playermodel )
1994 PRVM_GETEDICTFIELDVALUE(e, eval_playermodel)->string = PRVM_SetEngineString(svs.clients[num].playermodel);
1995 if( eval_playerskin )
1996 PRVM_GETEDICTFIELDVALUE(e, eval_playerskin)->string = PRVM_SetEngineString(svs.clients[num].playerskin);
2000 void SV_VM_CB_FreeEdict(prvm_edict_t *ed)
2002 SV_UnlinkEdict (ed); // unlink from world bsp
2004 ed->fields.server->model = 0;
2005 ed->fields.server->takedamage = 0;
2006 ed->fields.server->modelindex = 0;
2007 ed->fields.server->colormap = 0;
2008 ed->fields.server->skin = 0;
2009 ed->fields.server->frame = 0;
2010 VectorClear(ed->fields.server->origin);
2011 VectorClear(ed->fields.server->angles);
2012 ed->fields.server->nextthink = -1;
2013 ed->fields.server->solid = 0;
2016 void SV_VM_CB_CountEdicts(void)
2020 int active, models, solid, step;
2022 active = models = solid = step = 0;
2023 for (i=0 ; i<prog->num_edicts ; i++)
2025 ent = PRVM_EDICT_NUM(i);
2026 if (ent->priv.server->free)
2029 if (ent->fields.server->solid)
2031 if (ent->fields.server->model)
2033 if (ent->fields.server->movetype == MOVETYPE_STEP)
2037 Con_Printf("num_edicts:%3i\n", prog->num_edicts);
2038 Con_Printf("active :%3i\n", active);
2039 Con_Printf("view :%3i\n", models);
2040 Con_Printf("touch :%3i\n", solid);
2041 Con_Printf("step :%3i\n", step);
2044 qboolean SV_VM_CB_LoadEdict(prvm_edict_t *ent)
2046 // remove things from different skill levels or deathmatch
2047 if (gamemode != GAME_TRANSFUSION) //Transfusion does this in QC
2049 if (deathmatch.integer)
2051 if (((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
2056 else if ((current_skill <= 0 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_EASY ))
2057 || (current_skill == 1 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_MEDIUM))
2058 || (current_skill >= 2 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_HARD )))
2066 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)"};
2067 cvar_t nomonsters = {0, "nomonsters", "0", "unused cvar in quake, can be used by mods"};
2068 cvar_t gamecfg = {0, "gamecfg", "0", "unused cvar in quake, can be used by mods"};
2069 cvar_t scratch1 = {0, "scratch1", "0", "unused cvar in quake, can be used by mods"};
2070 cvar_t scratch2 = {0,"scratch2", "0", "unused cvar in quake, can be used by mods"};
2071 cvar_t scratch3 = {0, "scratch3", "0", "unused cvar in quake, can be used by mods"};
2072 cvar_t scratch4 = {0, "scratch4", "0", "unused cvar in quake, can be used by mods"};
2073 cvar_t savedgamecfg = {CVAR_SAVE, "savedgamecfg", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2074 cvar_t saved1 = {CVAR_SAVE, "saved1", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2075 cvar_t saved2 = {CVAR_SAVE, "saved2", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2076 cvar_t saved3 = {CVAR_SAVE, "saved3", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2077 cvar_t saved4 = {CVAR_SAVE, "saved4", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2078 cvar_t nehx00 = {0, "nehx00", "0", "nehahra data storage cvar (used in singleplayer)"};
2079 cvar_t nehx01 = {0, "nehx01", "0", "nehahra data storage cvar (used in singleplayer)"};
2080 cvar_t nehx02 = {0, "nehx02", "0", "nehahra data storage cvar (used in singleplayer)"};
2081 cvar_t nehx03 = {0, "nehx03", "0", "nehahra data storage cvar (used in singleplayer)"};
2082 cvar_t nehx04 = {0, "nehx04", "0", "nehahra data storage cvar (used in singleplayer)"};
2083 cvar_t nehx05 = {0, "nehx05", "0", "nehahra data storage cvar (used in singleplayer)"};
2084 cvar_t nehx06 = {0, "nehx06", "0", "nehahra data storage cvar (used in singleplayer)"};
2085 cvar_t nehx07 = {0, "nehx07", "0", "nehahra data storage cvar (used in singleplayer)"};
2086 cvar_t nehx08 = {0, "nehx08", "0", "nehahra data storage cvar (used in singleplayer)"};
2087 cvar_t nehx09 = {0, "nehx09", "0", "nehahra data storage cvar (used in singleplayer)"};
2088 cvar_t nehx10 = {0, "nehx10", "0", "nehahra data storage cvar (used in singleplayer)"};
2089 cvar_t nehx11 = {0, "nehx11", "0", "nehahra data storage cvar (used in singleplayer)"};
2090 cvar_t nehx12 = {0, "nehx12", "0", "nehahra data storage cvar (used in singleplayer)"};
2091 cvar_t nehx13 = {0, "nehx13", "0", "nehahra data storage cvar (used in singleplayer)"};
2092 cvar_t nehx14 = {0, "nehx14", "0", "nehahra data storage cvar (used in singleplayer)"};
2093 cvar_t nehx15 = {0, "nehx15", "0", "nehahra data storage cvar (used in singleplayer)"};
2094 cvar_t nehx16 = {0, "nehx16", "0", "nehahra data storage cvar (used in singleplayer)"};
2095 cvar_t nehx17 = {0, "nehx17", "0", "nehahra data storage cvar (used in singleplayer)"};
2096 cvar_t nehx18 = {0, "nehx18", "0", "nehahra data storage cvar (used in singleplayer)"};
2097 cvar_t nehx19 = {0, "nehx19", "0", "nehahra data storage cvar (used in singleplayer)"};
2098 cvar_t cutscene = {0, "cutscene", "1", "enables cutscenes in nehahra, can be used by other mods"};
2100 void SV_VM_Init(void)
2102 Cvar_RegisterVariable (&pr_checkextension);
2103 Cvar_RegisterVariable (&nomonsters);
2104 Cvar_RegisterVariable (&gamecfg);
2105 Cvar_RegisterVariable (&scratch1);
2106 Cvar_RegisterVariable (&scratch2);
2107 Cvar_RegisterVariable (&scratch3);
2108 Cvar_RegisterVariable (&scratch4);
2109 Cvar_RegisterVariable (&savedgamecfg);
2110 Cvar_RegisterVariable (&saved1);
2111 Cvar_RegisterVariable (&saved2);
2112 Cvar_RegisterVariable (&saved3);
2113 Cvar_RegisterVariable (&saved4);
2114 // LordHavoc: Nehahra uses these to pass data around cutscene demos
2115 if (gamemode == GAME_NEHAHRA)
2117 Cvar_RegisterVariable (&nehx00);
2118 Cvar_RegisterVariable (&nehx01);
2119 Cvar_RegisterVariable (&nehx02);
2120 Cvar_RegisterVariable (&nehx03);
2121 Cvar_RegisterVariable (&nehx04);
2122 Cvar_RegisterVariable (&nehx05);
2123 Cvar_RegisterVariable (&nehx06);
2124 Cvar_RegisterVariable (&nehx07);
2125 Cvar_RegisterVariable (&nehx08);
2126 Cvar_RegisterVariable (&nehx09);
2127 Cvar_RegisterVariable (&nehx10);
2128 Cvar_RegisterVariable (&nehx11);
2129 Cvar_RegisterVariable (&nehx12);
2130 Cvar_RegisterVariable (&nehx13);
2131 Cvar_RegisterVariable (&nehx14);
2132 Cvar_RegisterVariable (&nehx15);
2133 Cvar_RegisterVariable (&nehx16);
2134 Cvar_RegisterVariable (&nehx17);
2135 Cvar_RegisterVariable (&nehx18);
2136 Cvar_RegisterVariable (&nehx19);
2138 Cvar_RegisterVariable (&cutscene); // for Nehahra but useful to other mods as well
2141 // LordHavoc: in an effort to eliminate time wasted on GetEdictFieldValue... these are defined as externs in progs.h
2158 int eval_buttonchat;
2160 int eval_glow_trail;
2161 int eval_glow_color;
2165 int eval_renderamt; // HalfLife support
2166 int eval_rendermode; // HalfLife support
2167 int eval_fullbright;
2168 int eval_ammo_shells1;
2169 int eval_ammo_nails1;
2170 int eval_ammo_lava_nails;
2171 int eval_ammo_rockets1;
2172 int eval_ammo_multi_rockets;
2173 int eval_ammo_cells1;
2174 int eval_ammo_plasma;
2175 int eval_idealpitch;
2176 int eval_pitch_speed;
2177 int eval_viewmodelforclient;
2178 int eval_nodrawtoclient;
2179 int eval_exteriormodeltoclient;
2180 int eval_drawonlytoclient;
2184 int eval_punchvector;
2186 int eval_clientcolors;
2187 int eval_tag_entity;
2193 int eval_cursor_active;
2194 int eval_cursor_screen;
2195 int eval_cursor_trace_start;
2196 int eval_cursor_trace_endpos;
2197 int eval_cursor_trace_ent;
2199 int eval_playermodel;
2200 int eval_playerskin;
2201 int eval_SendEntity;
2203 int eval_customizeentityforclient;
2205 mfunction_t *SV_PlayerPhysicsQC;
2206 mfunction_t *EndFrameQC;
2207 //KrimZon - SERVER COMMANDS IN QUAKEC
2208 mfunction_t *SV_ParseClientCommandQC;
2210 ddef_t *PRVM_ED_FindGlobal(const char *name);
2212 void SV_VM_FindEdictFieldOffsets(void)
2214 eval_gravity = PRVM_ED_FindFieldOffset("gravity");
2215 eval_button3 = PRVM_ED_FindFieldOffset("button3");
2216 eval_button4 = PRVM_ED_FindFieldOffset("button4");
2217 eval_button5 = PRVM_ED_FindFieldOffset("button5");
2218 eval_button6 = PRVM_ED_FindFieldOffset("button6");
2219 eval_button7 = PRVM_ED_FindFieldOffset("button7");
2220 eval_button8 = PRVM_ED_FindFieldOffset("button8");
2221 eval_button9 = PRVM_ED_FindFieldOffset("button9");
2222 eval_button10 = PRVM_ED_FindFieldOffset("button10");
2223 eval_button11 = PRVM_ED_FindFieldOffset("button11");
2224 eval_button12 = PRVM_ED_FindFieldOffset("button12");
2225 eval_button13 = PRVM_ED_FindFieldOffset("button13");
2226 eval_button14 = PRVM_ED_FindFieldOffset("button14");
2227 eval_button15 = PRVM_ED_FindFieldOffset("button15");
2228 eval_button16 = PRVM_ED_FindFieldOffset("button16");
2229 eval_buttonuse = PRVM_ED_FindFieldOffset("buttonuse");
2230 eval_buttonchat = PRVM_ED_FindFieldOffset("buttonchat");
2231 eval_glow_size = PRVM_ED_FindFieldOffset("glow_size");
2232 eval_glow_trail = PRVM_ED_FindFieldOffset("glow_trail");
2233 eval_glow_color = PRVM_ED_FindFieldOffset("glow_color");
2234 eval_items2 = PRVM_ED_FindFieldOffset("items2");
2235 eval_scale = PRVM_ED_FindFieldOffset("scale");
2236 eval_alpha = PRVM_ED_FindFieldOffset("alpha");
2237 eval_renderamt = PRVM_ED_FindFieldOffset("renderamt"); // HalfLife support
2238 eval_rendermode = PRVM_ED_FindFieldOffset("rendermode"); // HalfLife support
2239 eval_fullbright = PRVM_ED_FindFieldOffset("fullbright");
2240 eval_ammo_shells1 = PRVM_ED_FindFieldOffset("ammo_shells1");
2241 eval_ammo_nails1 = PRVM_ED_FindFieldOffset("ammo_nails1");
2242 eval_ammo_lava_nails = PRVM_ED_FindFieldOffset("ammo_lava_nails");
2243 eval_ammo_rockets1 = PRVM_ED_FindFieldOffset("ammo_rockets1");
2244 eval_ammo_multi_rockets = PRVM_ED_FindFieldOffset("ammo_multi_rockets");
2245 eval_ammo_cells1 = PRVM_ED_FindFieldOffset("ammo_cells1");
2246 eval_ammo_plasma = PRVM_ED_FindFieldOffset("ammo_plasma");
2247 eval_idealpitch = PRVM_ED_FindFieldOffset("idealpitch");
2248 eval_pitch_speed = PRVM_ED_FindFieldOffset("pitch_speed");
2249 eval_viewmodelforclient = PRVM_ED_FindFieldOffset("viewmodelforclient");
2250 eval_nodrawtoclient = PRVM_ED_FindFieldOffset("nodrawtoclient");
2251 eval_exteriormodeltoclient = PRVM_ED_FindFieldOffset("exteriormodeltoclient");
2252 eval_drawonlytoclient = PRVM_ED_FindFieldOffset("drawonlytoclient");
2253 eval_ping = PRVM_ED_FindFieldOffset("ping");
2254 eval_movement = PRVM_ED_FindFieldOffset("movement");
2255 eval_pmodel = PRVM_ED_FindFieldOffset("pmodel");
2256 eval_punchvector = PRVM_ED_FindFieldOffset("punchvector");
2257 eval_viewzoom = PRVM_ED_FindFieldOffset("viewzoom");
2258 eval_clientcolors = PRVM_ED_FindFieldOffset("clientcolors");
2259 eval_tag_entity = PRVM_ED_FindFieldOffset("tag_entity");
2260 eval_tag_index = PRVM_ED_FindFieldOffset("tag_index");
2261 eval_light_lev = PRVM_ED_FindFieldOffset("light_lev");
2262 eval_color = PRVM_ED_FindFieldOffset("color");
2263 eval_style = PRVM_ED_FindFieldOffset("style");
2264 eval_pflags = PRVM_ED_FindFieldOffset("pflags");
2265 eval_cursor_active = PRVM_ED_FindFieldOffset("cursor_active");
2266 eval_cursor_screen = PRVM_ED_FindFieldOffset("cursor_screen");
2267 eval_cursor_trace_start = PRVM_ED_FindFieldOffset("cursor_trace_start");
2268 eval_cursor_trace_endpos = PRVM_ED_FindFieldOffset("cursor_trace_endpos");
2269 eval_cursor_trace_ent = PRVM_ED_FindFieldOffset("cursor_trace_ent");
2270 eval_colormod = PRVM_ED_FindFieldOffset("colormod");
2271 eval_playermodel = PRVM_ED_FindFieldOffset("playermodel");
2272 eval_playerskin = PRVM_ED_FindFieldOffset("playerskin");
2273 eval_SendEntity = PRVM_ED_FindFieldOffset("SendEntity");
2274 eval_Version = PRVM_ED_FindFieldOffset("Version");
2275 eval_customizeentityforclient = PRVM_ED_FindFieldOffset("customizeentityforclient");
2277 // LordHavoc: allowing QuakeC to override the player movement code
2278 SV_PlayerPhysicsQC = PRVM_ED_FindFunction ("SV_PlayerPhysics");
2279 // LordHavoc: support for endframe
2280 EndFrameQC = PRVM_ED_FindFunction ("EndFrame");
2281 //KrimZon - SERVER COMMANDS IN QUAKEC
2282 SV_ParseClientCommandQC = PRVM_ED_FindFunction ("SV_ParseClientCommand");
2284 //[515]: init stufftext string (it is sent before svc_serverinfo)
2285 if(PRVM_ED_FindGlobal("SV_InitCmd") && PRVM_ED_FindGlobal("SV_InitCmd")->type & ev_string)
2286 SV_InitCmd = PRVM_G_STRING(PRVM_ED_FindGlobal("SV_InitCmd")->ofs);
2291 #define REQFIELDS (sizeof(reqfields) / sizeof(prvm_required_field_t))
2293 prvm_required_field_t reqfields[] =
2295 {ev_entity, "cursor_trace_ent"},
2296 {ev_entity, "drawonlytoclient"},
2297 {ev_entity, "exteriormodeltoclient"},
2298 {ev_entity, "nodrawtoclient"},
2299 {ev_entity, "tag_entity"},
2300 {ev_entity, "viewmodelforclient"},
2301 {ev_float, "alpha"},
2302 {ev_float, "ammo_cells1"},
2303 {ev_float, "ammo_lava_nails"},
2304 {ev_float, "ammo_multi_rockets"},
2305 {ev_float, "ammo_nails1"},
2306 {ev_float, "ammo_plasma"},
2307 {ev_float, "ammo_rockets1"},
2308 {ev_float, "ammo_shells1"},
2309 {ev_float, "button3"},
2310 {ev_float, "button4"},
2311 {ev_float, "button5"},
2312 {ev_float, "button6"},
2313 {ev_float, "button7"},
2314 {ev_float, "button8"},
2315 {ev_float, "button9"},
2316 {ev_float, "button10"},
2317 {ev_float, "button11"},
2318 {ev_float, "button12"},
2319 {ev_float, "button13"},
2320 {ev_float, "button14"},
2321 {ev_float, "button15"},
2322 {ev_float, "button16"},
2323 {ev_float, "buttonchat"},
2324 {ev_float, "buttonuse"},
2325 {ev_float, "clientcolors"},
2326 {ev_float, "cursor_active"},
2327 {ev_float, "fullbright"},
2328 {ev_float, "glow_color"},
2329 {ev_float, "glow_size"},
2330 {ev_float, "glow_trail"},
2331 {ev_float, "gravity"},
2332 {ev_float, "idealpitch"},
2333 {ev_float, "items2"},
2334 {ev_float, "light_lev"},
2335 {ev_float, "pflags"},
2337 {ev_float, "pitch_speed"},
2338 {ev_float, "pmodel"},
2339 {ev_float, "renderamt"}, // HalfLife support
2340 {ev_float, "rendermode"}, // HalfLife support
2341 {ev_float, "scale"},
2342 {ev_float, "style"},
2343 {ev_float, "tag_index"},
2344 {ev_float, "Version"},
2345 {ev_float, "viewzoom"},
2346 {ev_vector, "color"},
2347 {ev_vector, "colormod"},
2348 {ev_vector, "cursor_screen"},
2349 {ev_vector, "cursor_trace_endpos"},
2350 {ev_vector, "cursor_trace_start"},
2351 {ev_vector, "movement"},
2352 {ev_vector, "punchvector"},
2353 {ev_string, "playermodel"},
2354 {ev_string, "playerskin"},
2355 {ev_function, "SendEntity"},
2356 {ev_function, "customizeentityforclient"},
2359 void SV_VM_Setup(void)
2362 PRVM_InitProg( PRVM_SERVERPROG );
2364 // allocate the mempools
2365 prog->progs_mempool = Mem_AllocPool("Server Progs", 0, NULL);
2366 prog->builtins = vm_sv_builtins;
2367 prog->numbuiltins = vm_sv_numbuiltins;
2368 prog->headercrc = PROGHEADER_CRC;
2369 prog->max_edicts = 512;
2370 prog->limit_edicts = MAX_EDICTS;
2371 prog->reserved_edicts = svs.maxclients;
2372 prog->edictprivate_size = sizeof(edict_engineprivate_t);
2373 prog->name = "server";
2374 prog->extensionstring = vm_sv_extensions;
2375 prog->loadintoworld = true;
2377 prog->begin_increase_edicts = SV_VM_CB_BeginIncreaseEdicts;
2378 prog->end_increase_edicts = SV_VM_CB_EndIncreaseEdicts;
2379 prog->init_edict = SV_VM_CB_InitEdict;
2380 prog->free_edict = SV_VM_CB_FreeEdict;
2381 prog->count_edicts = SV_VM_CB_CountEdicts;
2382 prog->load_edict = SV_VM_CB_LoadEdict;
2383 prog->init_cmd = VM_SV_Cmd_Init;
2384 prog->reset_cmd = VM_SV_Cmd_Reset;
2385 prog->error_cmd = Host_Error;
2387 // TODO: add a requiredfuncs list (ask LH if this is necessary at all)
2388 PRVM_LoadProgs( sv_progs.string, 0, NULL, REQFIELDS, reqfields );
2389 SV_VM_FindEdictFieldOffsets();
2391 VM_AutoSentStats_Clear();//[515]: csqc
2392 EntityFrameCSQC_ClearVersions();//[515]: csqc
2397 void SV_VM_Begin(void)
2400 PRVM_SetProg( PRVM_SERVERPROG );
2402 *prog->time = (float) sv.time;
2405 void SV_VM_End(void)