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", "0", "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"};
52 cvar_t sv_gameplayfix_qwplayerphysics = {0, "sv_gameplayfix_qwplayerphysics", "1", "changes water jumping to make it easier to get out of water, and prevents friction on landing when bunnyhopping"};
54 cvar_t sv_progs = {0, "sv_progs", "progs.dat", "selects which quakec progs.dat file to run" };
56 // TODO: move these cvars here
57 extern cvar_t sv_clmovement_enable;
58 extern cvar_t sv_clmovement_minping;
59 extern cvar_t sv_clmovement_minping_disabletime;
64 mempool_t *sv_mempool = NULL;
66 //============================================================================
68 extern void SV_Phys_Init (void);
69 extern void SV_World_Init (void);
70 static void SV_SaveEntFile_f(void);
79 Cmd_AddCommand("sv_saveentfile", SV_SaveEntFile_f, "save map entities to .ent file (to allow external editing)");
80 Cvar_RegisterVariable (&sv_maxvelocity);
81 Cvar_RegisterVariable (&sv_gravity);
82 Cvar_RegisterVariable (&sv_friction);
83 Cvar_RegisterVariable (&sv_waterfriction);
84 Cvar_RegisterVariable (&sv_edgefriction);
85 Cvar_RegisterVariable (&sv_stopspeed);
86 Cvar_RegisterVariable (&sv_maxspeed);
87 Cvar_RegisterVariable (&sv_maxairspeed);
88 Cvar_RegisterVariable (&sv_accelerate);
89 Cvar_RegisterVariable (&sv_airaccelerate);
90 Cvar_RegisterVariable (&sv_wateraccelerate);
91 Cvar_RegisterVariable (&sv_clmovement_enable);
92 Cvar_RegisterVariable (&sv_clmovement_minping);
93 Cvar_RegisterVariable (&sv_clmovement_minping_disabletime);
94 Cvar_RegisterVariable (&sv_idealpitchscale);
95 Cvar_RegisterVariable (&sv_aim);
96 Cvar_RegisterVariable (&sv_nostep);
97 Cvar_RegisterVariable (&sv_cullentities_pvs);
98 Cvar_RegisterVariable (&sv_cullentities_trace);
99 Cvar_RegisterVariable (&sv_cullentities_stats);
100 Cvar_RegisterVariable (&sv_entpatch);
101 Cvar_RegisterVariable (&sv_gameplayfix_grenadebouncedownslopes);
102 Cvar_RegisterVariable (&sv_gameplayfix_noairborncorpse);
103 Cvar_RegisterVariable (&sv_gameplayfix_stepdown);
104 Cvar_RegisterVariable (&sv_gameplayfix_stepwhilejumping);
105 Cvar_RegisterVariable (&sv_gameplayfix_swiminbmodels);
106 Cvar_RegisterVariable (&sv_gameplayfix_setmodelrealbox);
107 Cvar_RegisterVariable (&sv_gameplayfix_blowupfallenzombies);
108 Cvar_RegisterVariable (&sv_gameplayfix_findradiusdistancetobox);
109 Cvar_RegisterVariable (&sv_gameplayfix_qwplayerphysics);
110 Cvar_RegisterVariable (&sv_protocolname);
111 Cvar_RegisterVariable (&sv_ratelimitlocalplayer);
112 Cvar_RegisterVariable (&sv_maxrate);
113 Cvar_RegisterVariable (&sv_progs);
119 sv_mempool = Mem_AllocPool("server", 0, NULL);
122 static void SV_SaveEntFile_f(void)
124 char basename[MAX_QPATH];
125 if (!sv.active || !sv.worldmodel)
127 Con_Print("Not running a server\n");
130 FS_StripExtension(sv.worldmodel->name, basename, sizeof(basename));
131 FS_WriteFile(va("%s.ent", basename), sv.worldmodel->brush.entities, (fs_offset_t)strlen(sv.worldmodel->brush.entities));
136 =============================================================================
140 =============================================================================
147 Make sure the event gets sent to all clients
150 void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count)
154 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-18)
156 MSG_WriteByte (&sv.datagram, svc_particle);
157 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
158 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
159 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
160 for (i=0 ; i<3 ; i++)
161 MSG_WriteChar (&sv.datagram, (int)bound(-128, dir[i]*16, 127));
162 MSG_WriteByte (&sv.datagram, count);
163 MSG_WriteByte (&sv.datagram, color);
170 Make sure the event gets sent to all clients
173 void SV_StartEffect (vec3_t org, int modelindex, int startframe, int framecount, int framerate)
175 if (modelindex >= 256 || startframe >= 256)
177 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-19)
179 MSG_WriteByte (&sv.datagram, svc_effect2);
180 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
181 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
182 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
183 MSG_WriteShort (&sv.datagram, modelindex);
184 MSG_WriteShort (&sv.datagram, startframe);
185 MSG_WriteByte (&sv.datagram, framecount);
186 MSG_WriteByte (&sv.datagram, framerate);
190 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-17)
192 MSG_WriteByte (&sv.datagram, svc_effect);
193 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
194 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
195 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
196 MSG_WriteByte (&sv.datagram, modelindex);
197 MSG_WriteByte (&sv.datagram, startframe);
198 MSG_WriteByte (&sv.datagram, framecount);
199 MSG_WriteByte (&sv.datagram, framerate);
207 Each entity can have eight independant sound sources, like voice,
210 Channel 0 is an auto-allocate channel, the others override anything
211 already running on that entity/channel pair.
213 An attenuation of 0 will play full volume everywhere in the level.
214 Larger attenuations will drop off. (max 4 attenuation)
218 void SV_StartSound (prvm_edict_t *entity, int channel, const char *sample, int volume, float attenuation)
220 int sound_num, field_mask, i, ent;
222 if (volume < 0 || volume > 255)
224 Con_Printf ("SV_StartSound: volume = %i\n", volume);
228 if (attenuation < 0 || attenuation > 4)
230 Con_Printf ("SV_StartSound: attenuation = %f\n", attenuation);
234 if (channel < 0 || channel > 7)
236 Con_Printf ("SV_StartSound: channel = %i\n", channel);
240 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-21)
243 // find precache number for sound
244 sound_num = SV_SoundIndex(sample, 1);
248 ent = PRVM_NUM_FOR_EDICT(entity);
251 if (volume != DEFAULT_SOUND_PACKET_VOLUME)
252 field_mask |= SND_VOLUME;
253 if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
254 field_mask |= SND_ATTENUATION;
256 field_mask |= SND_LARGEENTITY;
257 if (sound_num >= 256 || channel >= 8)
258 field_mask |= SND_LARGESOUND;
260 // directed messages go only to the entity they are targeted on
261 MSG_WriteByte (&sv.datagram, svc_sound);
262 MSG_WriteByte (&sv.datagram, field_mask);
263 if (field_mask & SND_VOLUME)
264 MSG_WriteByte (&sv.datagram, volume);
265 if (field_mask & SND_ATTENUATION)
266 MSG_WriteByte (&sv.datagram, (int)(attenuation*64));
267 if (field_mask & SND_LARGEENTITY)
269 MSG_WriteShort (&sv.datagram, ent);
270 MSG_WriteByte (&sv.datagram, channel);
273 MSG_WriteShort (&sv.datagram, (ent<<3) | channel);
274 if (field_mask & SND_LARGESOUND)
275 MSG_WriteShort (&sv.datagram, sound_num);
277 MSG_WriteByte (&sv.datagram, sound_num);
278 for (i = 0;i < 3;i++)
279 MSG_WriteCoord (&sv.datagram, entity->fields.server->origin[i]+0.5*(entity->fields.server->mins[i]+entity->fields.server->maxs[i]), sv.protocol);
283 ==============================================================================
287 ==============================================================================
290 static const char *SV_InitCmd; //[515]: svprogs able to send cmd to client on connect
291 extern qboolean csqc_loaded;
296 Sends the first message from the server to a connected client.
297 This will be sent on the initial connection and upon each server load.
300 void SV_SendServerinfo (client_t *client)
305 // we know that this client has a netconnection and thus is not a bot
307 // edicts get reallocated on level changes, so we need to update it here
308 client->edict = PRVM_EDICT_NUM((client - svs.clients) + 1);
310 // clear cached stuff that depends on the level
311 client->weaponmodel[0] = 0;
312 client->weaponmodelindex = 0;
314 // LordHavoc: clear entityframe tracking
315 client->latestframenum = 0;
317 if (client->entitydatabase)
318 EntityFrame_FreeDatabase(client->entitydatabase);
319 if (client->entitydatabase4)
320 EntityFrame4_FreeDatabase(client->entitydatabase4);
321 if (client->entitydatabase5)
322 EntityFrame5_FreeDatabase(client->entitydatabase5);
324 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
326 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3)
327 client->entitydatabase = EntityFrame_AllocDatabase(sv_mempool);
328 else if (sv.protocol == PROTOCOL_DARKPLACES4)
329 client->entitydatabase4 = EntityFrame4_AllocDatabase(sv_mempool);
331 client->entitydatabase5 = EntityFrame5_AllocDatabase(sv_mempool);
334 SZ_Clear (&client->netconnection->message);
335 MSG_WriteByte (&client->netconnection->message, svc_print);
336 dpsnprintf (message, sizeof (message), "\nServer: %s build %s (progs %i crc)", gamename, buildstring, prog->filecrc);
337 MSG_WriteString (&client->netconnection->message,message);
339 // FIXME: LordHavoc: this does not work on dedicated servers, needs fixing.
340 //[515]: init csprogs according to version of svprogs, check the crc, etc.
341 if(csqc_loaded && (cls.state == ca_dedicated || PRVM_NUM_FOR_EDICT(client->edict) != 1))
343 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
345 MSG_WriteString (&client->netconnection->message, va("csqc_progcrc %i;%s\n", csqc_progcrc.integer, SV_InitCmd));
347 MSG_WriteString (&client->netconnection->message, va("csqc_progcrc %i\n", csqc_progcrc.integer));
350 MSG_WriteByte (&client->netconnection->message, svc_serverinfo);
351 MSG_WriteLong (&client->netconnection->message, Protocol_NumberForEnum(sv.protocol));
352 MSG_WriteByte (&client->netconnection->message, svs.maxclients);
354 if (!coop.integer && deathmatch.integer)
355 MSG_WriteByte (&client->netconnection->message, GAME_DEATHMATCH);
357 MSG_WriteByte (&client->netconnection->message, GAME_COOP);
359 MSG_WriteString (&client->netconnection->message,PRVM_GetString(prog->edicts->fields.server->message));
361 for (i = 1;i < MAX_MODELS && sv.model_precache[i][0];i++)
362 MSG_WriteString (&client->netconnection->message, sv.model_precache[i]);
363 MSG_WriteByte (&client->netconnection->message, 0);
365 for (i = 1;i < MAX_SOUNDS && sv.sound_precache[i][0];i++)
366 MSG_WriteString (&client->netconnection->message, sv.sound_precache[i]);
367 MSG_WriteByte (&client->netconnection->message, 0);
370 MSG_WriteByte (&client->netconnection->message, svc_cdtrack);
371 MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
372 MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
375 MSG_WriteByte (&client->netconnection->message, svc_setview);
376 MSG_WriteShort (&client->netconnection->message, PRVM_NUM_FOR_EDICT(client->edict));
378 MSG_WriteByte (&client->netconnection->message, svc_signonnum);
379 MSG_WriteByte (&client->netconnection->message, 1);
381 client->spawned = false; // need prespawn, spawn, etc
388 Initializes a client_t for a new net connection. This will only be called
389 once for a player each game, not once for each level change.
392 void SV_ConnectClient (int clientnum, netconn_t *netconnection)
396 float spawn_parms[NUM_SPAWN_PARMS];
398 client = svs.clients + clientnum;
400 if(netconnection)//[515]: bots don't play with csqc =)
401 EntityFrameCSQC_InitClientVersions(clientnum, false);
403 // set up the client_t
405 memcpy (spawn_parms, client->spawn_parms, sizeof(spawn_parms));
406 memset (client, 0, sizeof(*client));
407 client->active = true;
408 client->netconnection = netconnection;
410 Con_DPrintf("Client %s connected\n", client->netconnection ? client->netconnection->address : "botclient");
412 strcpy(client->name, "unconnected");
413 strcpy(client->old_name, "unconnected");
414 client->spawned = false;
415 client->edict = PRVM_EDICT_NUM(clientnum+1);
416 if (client->netconnection)
417 client->netconnection->message.allowoverflow = true; // we can catch it
418 // updated by receiving "rate" command from client
419 client->rate = NET_MINRATE;
420 // no limits for local player
421 if (client->netconnection && LHNETADDRESS_GetAddressType(&client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP)
422 client->rate = 1000000000;
423 client->connecttime = realtime;
426 memcpy (client->spawn_parms, spawn_parms, sizeof(spawn_parms));
429 // call the progs to get default spawn parms for the new client
430 // set self to world to intentionally cause errors with broken SetNewParms code in some mods
431 prog->globals.server->self = 0;
432 PRVM_ExecuteProgram (prog->globals.server->SetNewParms, "QC function SetNewParms is missing");
433 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
434 client->spawn_parms[i] = (&prog->globals.server->parm1)[i];
436 // set up the entity for this client (including .colormap, .team, etc)
437 PRVM_ED_ClearEdict(client->edict);
440 // don't call SendServerinfo for a fresh botclient because its fields have
441 // not been set up by the qc yet
442 if (client->netconnection)
443 SV_SendServerinfo (client);
445 client->spawned = true;
450 ===============================================================================
454 ===============================================================================
463 void SV_ClearDatagram (void)
465 SZ_Clear (&sv.datagram);
469 =============================================================================
471 The PVS must include a small area around the client to allow head bobbing
472 or other small motion on the client side. Otherwise, a bob might cause an
473 entity that should be visible to not show up, especially when the bob
476 =============================================================================
479 int sv_writeentitiestoclient_pvsbytes;
480 unsigned char sv_writeentitiestoclient_pvs[MAX_MAP_LEAFS/8];
482 static int numsendentities;
483 static entity_state_t sendentities[MAX_EDICTS];
484 static entity_state_t *sendentitiesindex[MAX_EDICTS];
486 qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *cs, int e)
489 unsigned int modelindex, effects, flags, glowsize, lightstyle, lightpflags, light[4], specialvisibilityradius;
490 unsigned int customizeentityforclient;
492 vec3_t cullmins, cullmaxs;
496 // EF_NODRAW prevents sending for any reason except for your own
497 // client, so we must keep all clients in this superset
498 effects = (unsigned)ent->fields.server->effects;
500 // we can omit invisible entities with no effects that are not clients
501 // LordHavoc: this could kill tags attached to an invisible entity, I
502 // just hope we never have to support that case
503 i = (int)ent->fields.server->modelindex;
504 modelindex = (i >= 1 && i < MAX_MODELS && *PRVM_GetString(ent->fields.server->model)) ? i : 0;
507 i = (int)(PRVM_GETEDICTFIELDVALUE(ent, eval_glow_size)->_float * 0.25f);
508 glowsize = (unsigned char)bound(0, i, 255);
509 if (PRVM_GETEDICTFIELDVALUE(ent, eval_glow_trail)->_float)
510 flags |= RENDER_GLOWTRAIL;
512 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[0]*256;
513 light[0] = (unsigned short)bound(0, f, 65535);
514 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[1]*256;
515 light[1] = (unsigned short)bound(0, f, 65535);
516 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[2]*256;
517 light[2] = (unsigned short)bound(0, f, 65535);
518 f = PRVM_GETEDICTFIELDVALUE(ent, eval_light_lev)->_float;
519 light[3] = (unsigned short)bound(0, f, 65535);
520 lightstyle = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_style)->_float;
521 lightpflags = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_pflags)->_float;
523 if (gamemode == GAME_TENEBRAE)
525 // tenebrae's EF_FULLDYNAMIC conflicts with Q2's EF_NODRAW
529 lightpflags |= PFLAGS_FULLDYNAMIC;
531 // tenebrae's EF_GREEN conflicts with DP's EF_ADDITIVE
535 light[0] = (int)(0.2*256);
536 light[1] = (int)(1.0*256);
537 light[2] = (int)(0.2*256);
539 lightpflags |= PFLAGS_FULLDYNAMIC;
543 specialvisibilityradius = 0;
544 if (lightpflags & PFLAGS_FULLDYNAMIC)
545 specialvisibilityradius = max(specialvisibilityradius, light[3]);
547 specialvisibilityradius = max(specialvisibilityradius, glowsize * 4);
548 if (flags & RENDER_GLOWTRAIL)
549 specialvisibilityradius = max(specialvisibilityradius, 100);
550 if (effects & (EF_BRIGHTFIELD | EF_MUZZLEFLASH | EF_BRIGHTLIGHT | EF_DIMLIGHT | EF_RED | EF_BLUE | EF_FLAME | EF_STARDUST))
552 if (effects & EF_BRIGHTFIELD)
553 specialvisibilityradius = max(specialvisibilityradius, 80);
554 if (effects & EF_MUZZLEFLASH)
555 specialvisibilityradius = max(specialvisibilityradius, 100);
556 if (effects & EF_BRIGHTLIGHT)
557 specialvisibilityradius = max(specialvisibilityradius, 400);
558 if (effects & EF_DIMLIGHT)
559 specialvisibilityradius = max(specialvisibilityradius, 200);
560 if (effects & EF_RED)
561 specialvisibilityradius = max(specialvisibilityradius, 200);
562 if (effects & EF_BLUE)
563 specialvisibilityradius = max(specialvisibilityradius, 200);
564 if (effects & EF_FLAME)
565 specialvisibilityradius = max(specialvisibilityradius, 250);
566 if (effects & EF_STARDUST)
567 specialvisibilityradius = max(specialvisibilityradius, 100);
570 // early culling checks
571 // (final culling is done by SV_MarkWriteEntityStateToClient)
572 customizeentityforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_customizeentityforclient)->function;
573 if (!customizeentityforclient)
575 if (e > svs.maxclients && (!modelindex && !specialvisibilityradius))
577 // this 2 billion unit check is actually to detect NAN origins
578 // (we really don't want to send those)
579 if (VectorLength2(ent->fields.server->origin) > 2000000000.0*2000000000.0)
587 VectorCopy(ent->fields.server->origin, cs->origin);
588 VectorCopy(ent->fields.server->angles, cs->angles);
590 cs->effects = effects;
591 cs->colormap = (unsigned)ent->fields.server->colormap;
592 cs->modelindex = modelindex;
593 cs->skin = (unsigned)ent->fields.server->skin;
594 cs->frame = (unsigned)ent->fields.server->frame;
595 cs->viewmodelforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)->edict;
596 cs->exteriormodelforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_exteriormodeltoclient)->edict;
597 cs->nodrawtoclient = PRVM_GETEDICTFIELDVALUE(ent, eval_nodrawtoclient)->edict;
598 cs->drawonlytoclient = PRVM_GETEDICTFIELDVALUE(ent, eval_drawonlytoclient)->edict;
599 cs->customizeentityforclient = customizeentityforclient;
600 cs->tagentity = PRVM_GETEDICTFIELDVALUE(ent, eval_tag_entity)->edict;
601 cs->tagindex = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_tag_index)->_float;
602 cs->glowsize = glowsize;
604 // don't need to init cs->colormod because the defaultstate did that for us
605 //cs->colormod[0] = cs->colormod[1] = cs->colormod[2] = 32;
606 val = PRVM_GETEDICTFIELDVALUE(ent, eval_colormod);
607 if (val->vector[0] || val->vector[1] || val->vector[2])
609 i = (int)(val->vector[0] * 32.0f);cs->colormod[0] = bound(0, i, 255);
610 i = (int)(val->vector[1] * 32.0f);cs->colormod[1] = bound(0, i, 255);
611 i = (int)(val->vector[2] * 32.0f);cs->colormod[2] = bound(0, i, 255);
614 cs->modelindex = modelindex;
617 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_alpha)->_float * 255.0f);
621 cs->alpha = (unsigned char)bound(0, i, 255);
624 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_renderamt)->_float);
628 cs->alpha = (unsigned char)bound(0, i, 255);
632 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_scale)->_float * 16.0f);
636 cs->scale = (unsigned char)bound(0, i, 255);
640 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_glow_color)->_float);
642 cs->glowcolor = (int)f;
644 if (PRVM_GETEDICTFIELDVALUE(ent, eval_fullbright)->_float)
645 cs->effects |= EF_FULLBRIGHT;
647 if (ent->fields.server->movetype == MOVETYPE_STEP)
648 cs->flags |= RENDER_STEP;
649 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)
650 cs->flags |= RENDER_LOWPRECISION;
651 if (ent->fields.server->colormap >= 1024)
652 cs->flags |= RENDER_COLORMAPPED;
653 if (cs->viewmodelforclient)
654 cs->flags |= RENDER_VIEWMODEL; // show relative to the view
656 cs->light[0] = light[0];
657 cs->light[1] = light[1];
658 cs->light[2] = light[2];
659 cs->light[3] = light[3];
660 cs->lightstyle = lightstyle;
661 cs->lightpflags = lightpflags;
663 cs->specialvisibilityradius = specialvisibilityradius;
665 // calculate the visible box of this entity (don't use the physics box
666 // as that is often smaller than a model, and would not count
667 // specialvisibilityradius)
668 if ((model = sv.models[modelindex]))
670 float scale = cs->scale * (1.0f / 16.0f);
671 if (cs->angles[0] || cs->angles[2]) // pitch and roll
673 VectorMA(cs->origin, scale, model->rotatedmins, cullmins);
674 VectorMA(cs->origin, scale, model->rotatedmaxs, cullmaxs);
676 else if (cs->angles[1])
678 VectorMA(cs->origin, scale, model->yawmins, cullmins);
679 VectorMA(cs->origin, scale, model->yawmaxs, cullmaxs);
683 VectorMA(cs->origin, scale, model->normalmins, cullmins);
684 VectorMA(cs->origin, scale, model->normalmaxs, cullmaxs);
689 // if there is no model (or it could not be loaded), use the physics box
690 VectorAdd(cs->origin, ent->fields.server->mins, cullmins);
691 VectorAdd(cs->origin, ent->fields.server->maxs, cullmaxs);
693 if (specialvisibilityradius)
695 cullmins[0] = min(cullmins[0], cs->origin[0] - specialvisibilityradius);
696 cullmins[1] = min(cullmins[1], cs->origin[1] - specialvisibilityradius);
697 cullmins[2] = min(cullmins[2], cs->origin[2] - specialvisibilityradius);
698 cullmaxs[0] = max(cullmaxs[0], cs->origin[0] + specialvisibilityradius);
699 cullmaxs[1] = max(cullmaxs[1], cs->origin[1] + specialvisibilityradius);
700 cullmaxs[2] = max(cullmaxs[2], cs->origin[2] + specialvisibilityradius);
702 if (!VectorCompare(cullmins, ent->priv.server->cullmins) || !VectorCompare(cullmaxs, ent->priv.server->cullmaxs))
704 VectorCopy(cullmins, ent->priv.server->cullmins);
705 VectorCopy(cullmaxs, ent->priv.server->cullmaxs);
706 ent->priv.server->pvs_numclusters = -1;
707 if (sv.worldmodel && sv.worldmodel->brush.FindBoxClusters)
709 i = sv.worldmodel->brush.FindBoxClusters(sv.worldmodel, cullmins, cullmaxs, MAX_ENTITYCLUSTERS, ent->priv.server->pvs_clusterlist);
710 if (i <= MAX_ENTITYCLUSTERS)
711 ent->priv.server->pvs_numclusters = i;
718 void SV_PrepareEntitiesForSending(void)
722 // send all entities that touch the pvs
724 sendentitiesindex[0] = NULL;
725 memset(sendentitiesindex, 0, prog->num_edicts * sizeof(entity_state_t *));
726 for (e = 1, ent = PRVM_NEXT_EDICT(prog->edicts);e < prog->num_edicts;e++, ent = PRVM_NEXT_EDICT(ent))
728 if (!ent->priv.server->free && SV_PrepareEntityForSending(ent, sendentities + numsendentities, e))
730 sendentitiesindex[e] = sendentities + numsendentities;
736 static int sententitiesmark = 0;
737 static int sententities[MAX_EDICTS];
738 static int sententitiesconsideration[MAX_EDICTS];
739 static int sv_writeentitiestoclient_culled_pvs;
740 static int sv_writeentitiestoclient_culled_trace;
741 static int sv_writeentitiestoclient_visibleentities;
742 static int sv_writeentitiestoclient_totalentities;
743 //static entity_frame_t sv_writeentitiestoclient_entityframe;
744 static int sv_writeentitiestoclient_clentnum;
745 static vec3_t sv_writeentitiestoclient_testeye;
746 static client_t *sv_writeentitiestoclient_client;
748 void SV_MarkWriteEntityStateToClient(entity_state_t *s)
755 if (sententitiesconsideration[s->number] == sententitiesmark)
757 sententitiesconsideration[s->number] = sententitiesmark;
758 sv_writeentitiestoclient_totalentities++;
760 if (s->customizeentityforclient)
762 prog->globals.server->self = s->number;
763 prog->globals.server->other = sv_writeentitiestoclient_clentnum;
764 PRVM_ExecuteProgram(s->customizeentityforclient, "customizeentityforclient: NULL function");
765 if(!PRVM_G_FLOAT(OFS_RETURN) || !SV_PrepareEntityForSending(PRVM_EDICT_NUM(s->number), s, s->number))
769 // never reject player
770 if (s->number != sv_writeentitiestoclient_clentnum)
772 // check various rejection conditions
773 if (s->nodrawtoclient == sv_writeentitiestoclient_clentnum)
775 if (s->drawonlytoclient && s->drawonlytoclient != sv_writeentitiestoclient_clentnum)
777 if (s->effects & EF_NODRAW)
779 // LordHavoc: only send entities with a model or important effects
780 if (!s->modelindex && s->specialvisibilityradius == 0)
783 // viewmodels don't have visibility checking
784 if (s->viewmodelforclient)
786 if (s->viewmodelforclient != sv_writeentitiestoclient_clentnum)
789 else if (s->tagentity)
791 // tag attached entities simply check their parent
792 if (!sendentitiesindex[s->tagentity])
794 SV_MarkWriteEntityStateToClient(sendentitiesindex[s->tagentity]);
795 if (sententities[s->tagentity] != sententitiesmark)
798 // always send world submodels in newer protocols because they don't
799 // generate much traffic (in old protocols they hog bandwidth)
800 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)))
802 // entity has survived every check so far, check if visible
803 ed = PRVM_EDICT_NUM(s->number);
805 // if not touching a visible leaf
806 if (sv_cullentities_pvs.integer && sv_writeentitiestoclient_pvsbytes)
808 if (ed->priv.server->pvs_numclusters < 0)
810 // entity too big for clusters list
811 if (sv.worldmodel && sv.worldmodel->brush.BoxTouchingPVS && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, sv_writeentitiestoclient_pvs, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
813 sv_writeentitiestoclient_culled_pvs++;
820 // check cached clusters list
821 for (i = 0;i < ed->priv.server->pvs_numclusters;i++)
822 if (CHECKPVSBIT(sv_writeentitiestoclient_pvs, ed->priv.server->pvs_clusterlist[i]))
824 if (i == ed->priv.server->pvs_numclusters)
826 sv_writeentitiestoclient_culled_pvs++;
832 // or not seen by random tracelines
833 if (sv_cullentities_trace.integer && !isbmodel)
835 // LordHavoc: test center first
836 testorigin[0] = (ed->priv.server->cullmins[0] + ed->priv.server->cullmaxs[0]) * 0.5f;
837 testorigin[1] = (ed->priv.server->cullmins[1] + ed->priv.server->cullmaxs[1]) * 0.5f;
838 testorigin[2] = (ed->priv.server->cullmins[2] + ed->priv.server->cullmaxs[2]) * 0.5f;
839 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
840 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
841 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
844 // LordHavoc: test random offsets, to maximize chance of detection
845 testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]);
846 testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]);
847 testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]);
848 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
849 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
850 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
853 if (s->specialvisibilityradius)
855 // LordHavoc: test random offsets, to maximize chance of detection
856 testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]);
857 testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]);
858 testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]);
859 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
860 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
861 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
865 if (realtime > sv_writeentitiestoclient_client->visibletime[s->number])
867 sv_writeentitiestoclient_culled_trace++;
874 // this just marks it for sending
875 // FIXME: it would be more efficient to send here, but the entity
876 // compressor isn't that flexible
877 sv_writeentitiestoclient_visibleentities++;
878 sententities[s->number] = sententitiesmark;
881 entity_state_t sendstates[MAX_EDICTS];
882 extern int csqc_clent;
884 void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t *msg, int *stats)
886 int i, numsendstates;
889 // if there isn't enough space to accomplish anything, skip it
890 if (msg->cursize + 25 > msg->maxsize)
893 sv_writeentitiestoclient_client = client;
895 sv_writeentitiestoclient_culled_pvs = 0;
896 sv_writeentitiestoclient_culled_trace = 0;
897 sv_writeentitiestoclient_visibleentities = 0;
898 sv_writeentitiestoclient_totalentities = 0;
900 // find the client's PVS
901 // the real place being tested from
902 VectorAdd(clent->fields.server->origin, clent->fields.server->view_ofs, sv_writeentitiestoclient_testeye);
903 sv_writeentitiestoclient_pvsbytes = 0;
904 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
905 sv_writeentitiestoclient_pvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, sv_writeentitiestoclient_testeye, 8, sv_writeentitiestoclient_pvs, sizeof(sv_writeentitiestoclient_pvs));
907 csqc_clent = sv_writeentitiestoclient_clentnum = PRVM_EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes
911 for (i = 0;i < numsendentities;i++)
912 SV_MarkWriteEntityStateToClient(sendentities + i);
915 for (i = 0;i < numsendentities;i++)
917 if (sententities[sendentities[i].number] == sententitiesmark)
919 s = &sendstates[numsendstates++];
920 *s = sendentities[i];
921 if (s->exteriormodelforclient && s->exteriormodelforclient == sv_writeentitiestoclient_clentnum)
922 s->flags |= RENDER_EXTERIORMODEL;
926 if (sv_cullentities_stats.integer)
927 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);
929 EntityFrameCSQC_WriteFrame(msg, numsendstates, sendstates);
931 if (client->entitydatabase5)
932 EntityFrame5_WriteFrame(msg, client->entitydatabase5, numsendstates, sendstates, client - svs.clients + 1, stats, client->movesequence);
933 else if (client->entitydatabase4)
934 EntityFrame4_WriteFrame(msg, client->entitydatabase4, numsendstates, sendstates);
935 else if (client->entitydatabase)
936 EntityFrame_WriteFrame(msg, client->entitydatabase, numsendstates, sendstates, client - svs.clients + 1);
938 EntityFrameQuake_WriteFrame(msg, numsendstates, sendstates);
947 void SV_CleanupEnts (void)
952 ent = PRVM_NEXT_EDICT(prog->edicts);
953 for (e=1 ; e<prog->num_edicts ; e++, ent = PRVM_NEXT_EDICT(ent))
954 ent->fields.server->effects = (int)ent->fields.server->effects & ~EF_MUZZLEFLASH;
959 SV_WriteClientdataToMessage
963 void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
975 // send a damage message
977 if (ent->fields.server->dmg_take || ent->fields.server->dmg_save)
979 other = PRVM_PROG_TO_EDICT(ent->fields.server->dmg_inflictor);
980 MSG_WriteByte (msg, svc_damage);
981 MSG_WriteByte (msg, (int)ent->fields.server->dmg_save);
982 MSG_WriteByte (msg, (int)ent->fields.server->dmg_take);
983 for (i=0 ; i<3 ; i++)
984 MSG_WriteCoord (msg, other->fields.server->origin[i] + 0.5*(other->fields.server->mins[i] + other->fields.server->maxs[i]), sv.protocol);
986 ent->fields.server->dmg_take = 0;
987 ent->fields.server->dmg_save = 0;
991 // send the current viewpos offset from the view entity
993 SV_SetIdealPitch (); // how much to look up / down ideally
995 // a fixangle might get lost in a dropped packet. Oh well.
996 if ( ent->fields.server->fixangle )
998 MSG_WriteByte (msg, svc_setangle);
999 for (i=0 ; i < 3 ; i++)
1000 MSG_WriteAngle (msg, ent->fields.server->angles[i], sv.protocol);
1001 ent->fields.server->fixangle = 0;
1004 // stuff the sigil bits into the high bits of items for sbar, or else
1006 val = PRVM_GETEDICTFIELDVALUE(ent, eval_items2);
1007 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
1008 items = (int)ent->fields.server->items | ((int)val->_float << 23);
1010 items = (int)ent->fields.server->items | ((int)prog->globals.server->serverflags << 28);
1012 VectorClear(punchvector);
1013 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_punchvector)))
1014 VectorCopy(val->vector, punchvector);
1016 // cache weapon model name and index in client struct to save time
1017 // (this search can be almost 1% of cpu time!)
1018 s = PRVM_GetString(ent->fields.server->weaponmodel);
1019 if (strcmp(s, client->weaponmodel))
1021 strlcpy(client->weaponmodel, s, sizeof(client->weaponmodel));
1022 client->weaponmodelindex = SV_ModelIndex(s, 1);
1026 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_viewzoom)))
1027 viewzoom = (int)(val->_float * 255.0f);
1033 if ((int)ent->fields.server->flags & FL_ONGROUND)
1034 bits |= SU_ONGROUND;
1035 if (ent->fields.server->waterlevel >= 2)
1037 if (ent->fields.server->idealpitch)
1038 bits |= SU_IDEALPITCH;
1040 for (i=0 ; i<3 ; i++)
1042 if (ent->fields.server->punchangle[i])
1043 bits |= (SU_PUNCH1<<i);
1044 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
1046 bits |= (SU_PUNCHVEC1<<i);
1047 if (ent->fields.server->velocity[i])
1048 bits |= (SU_VELOCITY1<<i);
1051 memset(stats, 0, sizeof(int[MAX_CL_STATS]));
1052 stats[STAT_VIEWHEIGHT] = (int)ent->fields.server->view_ofs[2];
1053 stats[STAT_ITEMS] = items;
1054 stats[STAT_WEAPONFRAME] = (int)ent->fields.server->weaponframe;
1055 stats[STAT_ARMOR] = (int)ent->fields.server->armorvalue;
1056 stats[STAT_WEAPON] = client->weaponmodelindex;
1057 stats[STAT_HEALTH] = (int)ent->fields.server->health;
1058 stats[STAT_AMMO] = (int)ent->fields.server->currentammo;
1059 stats[STAT_SHELLS] = (int)ent->fields.server->ammo_shells;
1060 stats[STAT_NAILS] = (int)ent->fields.server->ammo_nails;
1061 stats[STAT_ROCKETS] = (int)ent->fields.server->ammo_rockets;
1062 stats[STAT_CELLS] = (int)ent->fields.server->ammo_cells;
1063 stats[STAT_ACTIVEWEAPON] = (int)ent->fields.server->weapon;
1064 stats[STAT_VIEWZOOM] = viewzoom;
1065 // the QC bumps these itself by sending svc_'s, so we have to keep them
1066 // zero or they'll be corrected by the engine
1067 //stats[STAT_TOTALSECRETS] = prog->globals.server->total_secrets;
1068 //stats[STAT_TOTALMONSTERS] = prog->globals.server->total_monsters;
1069 //stats[STAT_SECRETS] = prog->globals.server->found_secrets;
1070 //stats[STAT_MONSTERS] = prog->globals.server->killed_monsters;
1072 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)
1074 if (stats[STAT_VIEWHEIGHT] != DEFAULT_VIEWHEIGHT) bits |= SU_VIEWHEIGHT;
1076 if (stats[STAT_WEAPONFRAME]) bits |= SU_WEAPONFRAME;
1077 if (stats[STAT_ARMOR]) bits |= SU_ARMOR;
1079 // FIXME: which protocols support this? does PROTOCOL_DARKPLACES3 support viewzoom?
1080 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
1081 if (viewzoom != 255)
1082 bits |= SU_VIEWZOOM;
1087 if (bits >= 16777216)
1091 MSG_WriteByte (msg, svc_clientdata);
1092 MSG_WriteShort (msg, bits);
1093 if (bits & SU_EXTEND1)
1094 MSG_WriteByte(msg, bits >> 16);
1095 if (bits & SU_EXTEND2)
1096 MSG_WriteByte(msg, bits >> 24);
1098 if (bits & SU_VIEWHEIGHT)
1099 MSG_WriteChar (msg, stats[STAT_VIEWHEIGHT]);
1101 if (bits & SU_IDEALPITCH)
1102 MSG_WriteChar (msg, (int)ent->fields.server->idealpitch);
1104 for (i=0 ; i<3 ; i++)
1106 if (bits & (SU_PUNCH1<<i))
1108 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1109 MSG_WriteChar(msg, (int)ent->fields.server->punchangle[i]);
1111 MSG_WriteAngle16i(msg, ent->fields.server->punchangle[i]);
1113 if (bits & (SU_PUNCHVEC1<<i))
1115 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1116 MSG_WriteCoord16i(msg, punchvector[i]);
1118 MSG_WriteCoord32f(msg, punchvector[i]);
1120 if (bits & (SU_VELOCITY1<<i))
1122 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1123 MSG_WriteChar(msg, (int)(ent->fields.server->velocity[i] * (1.0f / 16.0f)));
1125 MSG_WriteCoord32f(msg, ent->fields.server->velocity[i]);
1129 if (bits & SU_ITEMS)
1130 MSG_WriteLong (msg, stats[STAT_ITEMS]);
1132 if (sv.protocol == PROTOCOL_DARKPLACES5)
1134 if (bits & SU_WEAPONFRAME)
1135 MSG_WriteShort (msg, stats[STAT_WEAPONFRAME]);
1136 if (bits & SU_ARMOR)
1137 MSG_WriteShort (msg, stats[STAT_ARMOR]);
1138 if (bits & SU_WEAPON)
1139 MSG_WriteShort (msg, stats[STAT_WEAPON]);
1140 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1141 MSG_WriteShort (msg, stats[STAT_AMMO]);
1142 MSG_WriteShort (msg, stats[STAT_SHELLS]);
1143 MSG_WriteShort (msg, stats[STAT_NAILS]);
1144 MSG_WriteShort (msg, stats[STAT_ROCKETS]);
1145 MSG_WriteShort (msg, stats[STAT_CELLS]);
1146 MSG_WriteShort (msg, stats[STAT_ACTIVEWEAPON]);
1147 if (bits & SU_VIEWZOOM)
1148 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1150 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)
1152 if (bits & SU_WEAPONFRAME)
1153 MSG_WriteByte (msg, stats[STAT_WEAPONFRAME]);
1154 if (bits & SU_ARMOR)
1155 MSG_WriteByte (msg, stats[STAT_ARMOR]);
1156 if (bits & SU_WEAPON)
1157 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1158 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1159 MSG_WriteByte (msg, stats[STAT_AMMO]);
1160 MSG_WriteByte (msg, stats[STAT_SHELLS]);
1161 MSG_WriteByte (msg, stats[STAT_NAILS]);
1162 MSG_WriteByte (msg, stats[STAT_ROCKETS]);
1163 MSG_WriteByte (msg, stats[STAT_CELLS]);
1164 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_NEXUIZ)
1166 for (i = 0;i < 32;i++)
1167 if (stats[STAT_WEAPON] & (1<<i))
1169 MSG_WriteByte (msg, i);
1172 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1173 if (bits & SU_VIEWZOOM)
1175 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1176 MSG_WriteByte (msg, bound(0, stats[STAT_VIEWZOOM], 255));
1178 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1184 =======================
1185 SV_SendClientDatagram
1186 =======================
1188 static unsigned char sv_sendclientdatagram_buf[NET_MAXMESSAGE]; // FIXME?
1189 void SV_SendClientDatagram (client_t *client)
1191 int rate, maxrate, maxsize, maxsize2;
1193 int stats[MAX_CL_STATS];
1195 if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP && !sv_ratelimitlocalplayer.integer)
1197 // for good singleplayer, send huge packets
1198 maxsize = sizeof(sv_sendclientdatagram_buf);
1199 maxsize2 = sizeof(sv_sendclientdatagram_buf);
1201 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)
1203 // no rate limiting support on older protocols because dp protocols
1204 // 1-4 kick the client off if they overflow, and quake protocol shows
1205 // less than the full entity set if rate limited
1211 // PROTOCOL_DARKPLACES5 and later support packet size limiting of updates
1212 maxrate = bound(NET_MINRATE, sv_maxrate.integer, NET_MAXRATE);
1213 if (sv_maxrate.integer != maxrate)
1214 Cvar_SetValueQuick(&sv_maxrate, maxrate);
1216 // this rate limiting does not understand sys_ticrate 0
1217 // (but no one should be running that on a server!)
1218 rate = bound(NET_MINRATE, client->rate, maxrate);
1219 rate = (int)(client->rate * sys_ticrate.value);
1220 maxsize = bound(100, rate, 1400);
1224 msg.data = sv_sendclientdatagram_buf;
1225 msg.maxsize = maxsize;
1228 if (host_client->spawned)
1230 MSG_WriteByte (&msg, svc_time);
1231 MSG_WriteFloat (&msg, sv.time);
1233 // add the client specific data to the datagram
1234 SV_WriteClientdataToMessage (client, client->edict, &msg, stats);
1235 VM_SV_WriteAutoSentStats (client, client->edict, &msg, stats);
1236 SV_WriteEntitiesToClient (client, client->edict, &msg, stats);
1238 // expand packet size to allow effects to go over the rate limit
1239 // (dropping them is FAR too ugly)
1240 msg.maxsize = maxsize2;
1242 // copy the server datagram if there is space
1243 // FIXME: put in delayed queue of effects to send
1244 if (sv.datagram.cursize > 0 && msg.cursize + sv.datagram.cursize <= msg.maxsize)
1245 SZ_Write (&msg, sv.datagram.data, sv.datagram.cursize);
1247 else if (realtime > client->keepalivetime)
1249 // the player isn't totally in the game yet
1250 // send small keepalive messages if too much time has passed
1251 client->keepalivetime = realtime + 5;
1252 MSG_WriteChar (&msg, svc_nop);
1255 // send the datagram
1256 NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol);
1260 =======================
1261 SV_UpdateToReliableMessages
1262 =======================
1264 void SV_UpdateToReliableMessages (void)
1273 // check for changes to be sent over the reliable streams
1274 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1276 // update the host_client fields we care about according to the entity fields
1277 host_client->edict = PRVM_EDICT_NUM(i+1);
1280 name = PRVM_GetString(host_client->edict->fields.server->netname);
1283 // always point the string back at host_client->name to keep it safe
1284 strlcpy (host_client->name, name, sizeof (host_client->name));
1285 host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
1286 if (strcmp(host_client->old_name, host_client->name))
1288 if (host_client->spawned)
1289 SV_BroadcastPrintf("%s changed name to %s\n", host_client->old_name, host_client->name);
1290 strcpy(host_client->old_name, host_client->name);
1291 // send notification to all clients
1292 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
1293 MSG_WriteByte (&sv.reliable_datagram, i);
1294 MSG_WriteString (&sv.reliable_datagram, host_client->name);
1297 // DP_SV_CLIENTCOLORS
1298 // this is always found (since it's added by the progs loader)
1299 if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_clientcolors)))
1300 host_client->colors = (int)val->_float;
1301 if (host_client->old_colors != host_client->colors)
1303 host_client->old_colors = host_client->colors;
1304 // send notification to all clients
1305 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1306 MSG_WriteByte (&sv.reliable_datagram, i);
1307 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1310 // NEXUIZ_PLAYERMODEL
1311 if( eval_playermodel ) {
1312 model = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string);
1315 // always point the string back at host_client->name to keep it safe
1316 strlcpy (host_client->playermodel, model, sizeof (host_client->playermodel));
1317 PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
1320 // NEXUIZ_PLAYERSKIN
1321 if( eval_playerskin ) {
1322 skin = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string);
1325 // always point the string back at host_client->name to keep it safe
1326 strlcpy (host_client->playerskin, skin, sizeof (host_client->playerskin));
1327 PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
1331 host_client->frags = (int)host_client->edict->fields.server->frags;
1332 if (host_client->old_frags != host_client->frags)
1334 host_client->old_frags = host_client->frags;
1335 // send notification to all clients
1336 MSG_WriteByte (&sv.reliable_datagram, svc_updatefrags);
1337 MSG_WriteByte (&sv.reliable_datagram, i);
1338 MSG_WriteShort (&sv.reliable_datagram, host_client->frags);
1342 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1343 if (client->netconnection)
1344 SZ_Write (&client->netconnection->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
1346 SZ_Clear (&sv.reliable_datagram);
1351 =======================
1352 SV_SendClientMessages
1353 =======================
1355 void SV_SendClientMessages (void)
1357 int i, prepared = false;
1359 if (sv.protocol == PROTOCOL_QUAKEWORLD)
1360 Sys_Error("SV_SendClientMessages: no quakeworld support\n");
1362 // update frags, names, etc
1363 SV_UpdateToReliableMessages();
1365 // build individual updates
1366 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1368 if (!host_client->active)
1370 if (!host_client->netconnection)
1373 if (host_client->netconnection->message.overflowed)
1375 SV_DropClient (true); // if the message couldn't send, kick off
1382 // only prepare entities once per frame
1383 SV_PrepareEntitiesForSending();
1385 SV_SendClientDatagram (host_client);
1388 // clear muzzle flashes
1394 ==============================================================================
1398 ==============================================================================
1407 int SV_ModelIndex(const char *s, int precachemode)
1409 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_MODELS);
1410 char filename[MAX_QPATH];
1414 //if (precachemode == 2)
1416 strlcpy(filename, s, sizeof(filename));
1417 for (i = 2;i < limit;i++)
1419 if (!sv.model_precache[i][0])
1423 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))
1425 Con_Printf("SV_ModelIndex(\"%s\"): precache_model can only be done in spawn functions\n", filename);
1428 if (precachemode == 1)
1429 Con_Printf("SV_ModelIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1430 strlcpy(sv.model_precache[i], filename, sizeof(sv.model_precache[i]));
1431 sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, false);
1432 if (sv.state != ss_loading)
1434 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1435 MSG_WriteShort(&sv.reliable_datagram, i);
1436 MSG_WriteString(&sv.reliable_datagram, filename);
1440 Con_Printf("SV_ModelIndex(\"%s\"): not precached\n", filename);
1443 if (!strcmp(sv.model_precache[i], filename))
1446 Con_Printf("SV_ModelIndex(\"%s\"): i (%i) == MAX_MODELS (%i)\n", filename, i, MAX_MODELS);
1456 int SV_SoundIndex(const char *s, int precachemode)
1458 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_SOUNDS);
1459 char filename[MAX_QPATH];
1463 //if (precachemode == 2)
1465 strlcpy(filename, s, sizeof(filename));
1466 for (i = 1;i < limit;i++)
1468 if (!sv.sound_precache[i][0])
1472 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))
1474 Con_Printf("SV_SoundIndex(\"%s\"): precache_sound can only be done in spawn functions\n", filename);
1477 if (precachemode == 1)
1478 Con_Printf("SV_SoundIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1479 strlcpy(sv.sound_precache[i], filename, sizeof(sv.sound_precache[i]));
1480 if (sv.state != ss_loading)
1482 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1483 MSG_WriteShort(&sv.reliable_datagram, i + 32768);
1484 MSG_WriteString(&sv.reliable_datagram, filename);
1488 Con_Printf("SV_SoundIndex(\"%s\"): not precached\n", filename);
1491 if (!strcmp(sv.sound_precache[i], filename))
1494 Con_Printf("SV_SoundIndex(\"%s\"): i (%i) == MAX_SOUNDS (%i)\n", filename, i, MAX_SOUNDS);
1504 void SV_CreateBaseline (void)
1506 int i, entnum, large;
1507 prvm_edict_t *svent;
1509 // LordHavoc: clear *all* states (note just active ones)
1510 for (entnum = 0;entnum < prog->max_edicts;entnum++)
1512 // get the current server version
1513 svent = PRVM_EDICT_NUM(entnum);
1515 // LordHavoc: always clear state values, whether the entity is in use or not
1516 svent->priv.server->baseline = defaultstate;
1518 if (svent->priv.server->free)
1520 if (entnum > svs.maxclients && !svent->fields.server->modelindex)
1523 // create entity baseline
1524 VectorCopy (svent->fields.server->origin, svent->priv.server->baseline.origin);
1525 VectorCopy (svent->fields.server->angles, svent->priv.server->baseline.angles);
1526 svent->priv.server->baseline.frame = (int)svent->fields.server->frame;
1527 svent->priv.server->baseline.skin = (int)svent->fields.server->skin;
1528 if (entnum > 0 && entnum <= svs.maxclients)
1530 svent->priv.server->baseline.colormap = entnum;
1531 svent->priv.server->baseline.modelindex = SV_ModelIndex("progs/player.mdl", 1);
1535 svent->priv.server->baseline.colormap = 0;
1536 svent->priv.server->baseline.modelindex = (int)svent->fields.server->modelindex;
1540 if (svent->priv.server->baseline.modelindex & 0xFF00 || svent->priv.server->baseline.frame & 0xFF00)
1543 // add to the message
1545 MSG_WriteByte (&sv.signon, svc_spawnbaseline2);
1547 MSG_WriteByte (&sv.signon, svc_spawnbaseline);
1548 MSG_WriteShort (&sv.signon, entnum);
1552 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.modelindex);
1553 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.frame);
1557 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.modelindex);
1558 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.frame);
1560 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.colormap);
1561 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.skin);
1562 for (i=0 ; i<3 ; i++)
1564 MSG_WriteCoord(&sv.signon, svent->priv.server->baseline.origin[i], sv.protocol);
1565 MSG_WriteAngle(&sv.signon, svent->priv.server->baseline.angles[i], sv.protocol);
1575 Grabs the current state of each client for saving across the
1576 transition to another level
1579 void SV_SaveSpawnparms (void)
1583 svs.serverflags = (int)prog->globals.server->serverflags;
1585 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1587 if (!host_client->active)
1590 // call the progs to get default spawn parms for the new client
1591 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1592 PRVM_ExecuteProgram (prog->globals.server->SetChangeParms, "QC function SetChangeParms is missing");
1593 for (j=0 ; j<NUM_SPAWN_PARMS ; j++)
1594 host_client->spawn_parms[j] = (&prog->globals.server->parm1)[j];
1598 void SV_IncreaseEdicts(void)
1602 int oldmax_edicts = prog->max_edicts;
1603 void *oldedictsengineprivate = prog->edictprivate;
1604 void *oldedictsfields = prog->edictsfields;
1605 void *oldmoved_edicts = sv.moved_edicts;
1607 if (prog->max_edicts >= MAX_EDICTS)
1610 // links don't survive the transition, so unlink everything
1611 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1613 if (!ent->priv.server->free)
1614 SV_UnlinkEdict(prog->edicts + i);
1615 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
1619 prog->max_edicts = min(prog->max_edicts + 256, MAX_EDICTS);
1620 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
1621 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);
1622 sv.moved_edicts = PR_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1624 memcpy(prog->edictprivate, oldedictsengineprivate, oldmax_edicts * sizeof(edict_engineprivate_t));
1625 memcpy(prog->edictsfields, oldedictsfields, oldmax_edicts * prog->edict_size);
1627 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1629 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
1630 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
1631 // link every entity except world
1632 if (!ent->priv.server->free)
1633 SV_LinkEdict(ent, false);
1636 PR_Free(oldedictsengineprivate);
1637 PR_Free(oldedictsfields);
1638 PR_Free(oldmoved_edicts);
1645 This is called at the start of each level
1648 extern float scr_centertime_off;
1650 void SV_SpawnServer (const char *server)
1655 model_t *worldmodel;
1656 char modelname[sizeof(sv.modelname)];
1658 Con_DPrintf("SpawnServer: %s\n", server);
1660 if (cls.state != ca_dedicated)
1661 SCR_BeginLoadingPlaque();
1663 dpsnprintf (modelname, sizeof(modelname), "maps/%s.bsp", server);
1664 worldmodel = Mod_ForName(modelname, false, true, true);
1665 if (!worldmodel || !worldmodel->TraceBox)
1667 Con_Printf("Couldn't load map %s\n", modelname);
1671 // let's not have any servers with no name
1672 if (hostname.string[0] == 0)
1673 Cvar_Set ("hostname", "UNNAMED");
1674 scr_centertime_off = 0;
1676 svs.changelevel_issued = false; // now safe to issue another
1679 // tell all connected clients that we are going to a new level
1684 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
1686 if (client->netconnection)
1688 MSG_WriteByte(&client->netconnection->message, svc_stufftext);
1689 MSG_WriteString(&client->netconnection->message, "reconnect\n");
1696 NetConn_OpenServerPorts(true);
1700 // make cvars consistant
1703 Cvar_SetValue ("deathmatch", 0);
1704 // LordHavoc: it can be useful to have skills outside the range 0-3...
1705 //current_skill = bound(0, (int)(skill.value + 0.5), 3);
1706 //Cvar_SetValue ("skill", (float)current_skill);
1707 current_skill = (int)(skill.value + 0.5);
1710 // set up the new server
1712 memset (&sv, 0, sizeof(sv));
1713 // if running a local client, make sure it doesn't try to access the last
1714 // level's data which is no longer valiud
1721 strlcpy (sv.name, server, sizeof (sv.name));
1723 sv.protocol = Protocol_EnumForName(sv_protocolname.string);
1724 if (sv.protocol == PROTOCOL_UNKNOWN)
1727 Protocol_Names(buffer, sizeof(buffer));
1728 Con_Printf("Unknown sv_protocolname \"%s\", valid values are:\n%s\n", sv_protocolname.string, buffer);
1729 sv.protocol = PROTOCOL_QUAKE;
1734 // load progs to get entity field count
1735 //PR_LoadProgs ( sv_progs.string );
1737 // allocate server memory
1738 /*// start out with just enough room for clients and a reasonable estimate of entities
1739 prog->max_edicts = max(svs.maxclients + 1, 512);
1740 prog->max_edicts = min(prog->max_edicts, MAX_EDICTS);
1742 // prvm_edict_t structures (hidden from progs)
1743 prog->edicts = PR_Alloc(MAX_EDICTS * sizeof(prvm_edict_t));
1744 // engine private structures (hidden from progs)
1745 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
1746 // progs fields, often accessed by server
1747 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);*/
1748 // used by PushMove to move back pushed entities
1749 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1750 /*for (i = 0;i < prog->max_edicts;i++)
1752 ent = prog->edicts + i;
1753 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
1754 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
1757 // reset client csqc entity versions right away.
1758 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1759 EntityFrameCSQC_InitClientVersions(i, true);
1761 sv.datagram.maxsize = sizeof(sv.datagram_buf);
1762 sv.datagram.cursize = 0;
1763 sv.datagram.data = sv.datagram_buf;
1765 sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf);
1766 sv.reliable_datagram.cursize = 0;
1767 sv.reliable_datagram.data = sv.reliable_datagram_buf;
1769 sv.signon.maxsize = sizeof(sv.signon_buf);
1770 sv.signon.cursize = 0;
1771 sv.signon.data = sv.signon_buf;
1773 // leave slots at start for clients only
1774 //prog->num_edicts = svs.maxclients+1;
1776 sv.state = ss_loading;
1777 prog->allowworldwrites = true;
1780 *prog->time = sv.time = 1.0;
1783 worldmodel->used = true;
1785 strlcpy (sv.name, server, sizeof (sv.name));
1786 strcpy(sv.modelname, modelname);
1787 sv.worldmodel = worldmodel;
1788 sv.models[1] = sv.worldmodel;
1791 // clear world interaction links
1795 strlcpy(sv.sound_precache[0], "", sizeof(sv.sound_precache[0]));
1797 strlcpy(sv.model_precache[0], "", sizeof(sv.model_precache[0]));
1798 strlcpy(sv.model_precache[1], sv.modelname, sizeof(sv.model_precache[1]));
1799 for (i = 1;i < sv.worldmodel->brush.numsubmodels;i++)
1801 dpsnprintf(sv.model_precache[i+1], sizeof(sv.model_precache[i+1]), "*%i", i);
1802 sv.models[i+1] = Mod_ForName (sv.model_precache[i+1], false, false, false);
1806 // load the rest of the entities
1808 // AK possible hack since num_edicts is still 0
1809 ent = PRVM_EDICT_NUM(0);
1810 memset (ent->fields.server, 0, prog->progs->entityfields * 4);
1811 ent->priv.server->free = false;
1812 ent->fields.server->model = PRVM_SetEngineString(sv.modelname);
1813 ent->fields.server->modelindex = 1; // world model
1814 ent->fields.server->solid = SOLID_BSP;
1815 ent->fields.server->movetype = MOVETYPE_PUSH;
1818 prog->globals.server->coop = coop.integer;
1820 prog->globals.server->deathmatch = deathmatch.integer;
1822 prog->globals.server->mapname = PRVM_SetEngineString(sv.name);
1824 // serverflags are for cross level information (sigils)
1825 prog->globals.server->serverflags = svs.serverflags;
1827 // we need to reset the spawned flag on all connected clients here so that
1828 // their thinks don't run during startup (before PutClientInServer)
1829 // we also need to set up the client entities now
1830 // and we need to set the ->edict pointers to point into the progs edicts
1831 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1833 host_client->spawned = false;
1834 host_client->edict = PRVM_EDICT_NUM(i + 1);
1835 PRVM_ED_ClearEdict(host_client->edict);
1838 // load replacement entity file if found
1839 if (sv_entpatch.integer && (entities = (char *)FS_LoadFile(va("maps/%s.ent", sv.name), tempmempool, true, NULL)))
1841 Con_Printf("Loaded maps/%s.ent\n", sv.name);
1842 PRVM_ED_LoadFromFile (entities);
1846 PRVM_ED_LoadFromFile (sv.worldmodel->brush.entities);
1849 // LordHavoc: clear world angles (to fix e3m3.bsp)
1850 VectorClear(prog->edicts->fields.server->angles);
1852 // all setup is completed, any further precache statements are errors
1853 sv.state = ss_active;
1854 prog->allowworldwrites = false;
1856 // run two frames to allow everything to settle
1857 for (i = 0;i < 2;i++)
1865 // create a baseline for more efficient communications
1866 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1867 SV_CreateBaseline ();
1869 // send serverinfo to all connected clients, and set up botclients coming back from a level change
1870 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1872 if (!host_client->active)
1874 if (host_client->netconnection)
1875 SV_SendServerinfo(host_client);
1879 // if client is a botclient coming from a level change, we need to
1880 // set up client info that normally requires networking
1882 // copy spawn parms out of the client_t
1883 for (j=0 ; j< NUM_SPAWN_PARMS ; j++)
1884 (&prog->globals.server->parm1)[j] = host_client->spawn_parms[j];
1886 // call the spawn function
1887 host_client->clientconnectcalled = true;
1888 prog->globals.server->time = sv.time;
1889 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1890 PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
1891 PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
1892 host_client->spawned = true;
1896 Con_DPrint("Server spawned.\n");
1897 NetConn_Heartbeat (2);
1902 /////////////////////////////////////////////////////
1905 void SV_VM_CB_BeginIncreaseEdicts(void)
1910 PRVM_Free( sv.moved_edicts );
1911 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1913 // links don't survive the transition, so unlink everything
1914 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1916 if (!ent->priv.server->free)
1917 SV_UnlinkEdict(prog->edicts + i);
1918 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
1923 void SV_VM_CB_EndIncreaseEdicts(void)
1928 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1930 // link every entity except world
1931 if (!ent->priv.server->free)
1932 SV_LinkEdict(ent, false);
1936 void SV_VM_CB_InitEdict(prvm_edict_t *e)
1938 // LordHavoc: for consistency set these here
1939 int num = PRVM_NUM_FOR_EDICT(e) - 1;
1941 e->priv.server->move = false; // don't move on first frame
1943 if (num >= 0 && num < svs.maxclients)
1946 // set colormap and team on newly created player entity
1947 e->fields.server->colormap = num + 1;
1948 e->fields.server->team = (svs.clients[num].colors & 15) + 1;
1949 // set netname/clientcolors back to client values so that
1950 // DP_SV_CLIENTNAME and DP_SV_CLIENTCOLORS will not immediately
1952 e->fields.server->netname = PRVM_SetEngineString(svs.clients[num].name);
1953 if ((val = PRVM_GETEDICTFIELDVALUE(e, eval_clientcolors)))
1954 val->_float = svs.clients[num].colors;
1955 // NEXUIZ_PLAYERMODEL and NEXUIZ_PLAYERSKIN
1956 if( eval_playermodel )
1957 PRVM_GETEDICTFIELDVALUE(e, eval_playermodel)->string = PRVM_SetEngineString(svs.clients[num].playermodel);
1958 if( eval_playerskin )
1959 PRVM_GETEDICTFIELDVALUE(e, eval_playerskin)->string = PRVM_SetEngineString(svs.clients[num].playerskin);
1963 void SV_VM_CB_FreeEdict(prvm_edict_t *ed)
1965 SV_UnlinkEdict (ed); // unlink from world bsp
1967 ed->fields.server->model = 0;
1968 ed->fields.server->takedamage = 0;
1969 ed->fields.server->modelindex = 0;
1970 ed->fields.server->colormap = 0;
1971 ed->fields.server->skin = 0;
1972 ed->fields.server->frame = 0;
1973 VectorClear(ed->fields.server->origin);
1974 VectorClear(ed->fields.server->angles);
1975 ed->fields.server->nextthink = -1;
1976 ed->fields.server->solid = 0;
1979 void SV_VM_CB_CountEdicts(void)
1983 int active, models, solid, step;
1985 active = models = solid = step = 0;
1986 for (i=0 ; i<prog->num_edicts ; i++)
1988 ent = PRVM_EDICT_NUM(i);
1989 if (ent->priv.server->free)
1992 if (ent->fields.server->solid)
1994 if (ent->fields.server->model)
1996 if (ent->fields.server->movetype == MOVETYPE_STEP)
2000 Con_Printf("num_edicts:%3i\n", prog->num_edicts);
2001 Con_Printf("active :%3i\n", active);
2002 Con_Printf("view :%3i\n", models);
2003 Con_Printf("touch :%3i\n", solid);
2004 Con_Printf("step :%3i\n", step);
2007 qboolean SV_VM_CB_LoadEdict(prvm_edict_t *ent)
2009 // remove things from different skill levels or deathmatch
2010 if (gamemode != GAME_TRANSFUSION) //Transfusion does this in QC
2012 if (deathmatch.integer)
2014 if (((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
2019 else if ((current_skill <= 0 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_EASY ))
2020 || (current_skill == 1 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_MEDIUM))
2021 || (current_skill >= 2 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_HARD )))
2029 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)"};
2030 cvar_t nomonsters = {0, "nomonsters", "0", "unused cvar in quake, can be used by mods"};
2031 cvar_t gamecfg = {0, "gamecfg", "0", "unused cvar in quake, can be used by mods"};
2032 cvar_t scratch1 = {0, "scratch1", "0", "unused cvar in quake, can be used by mods"};
2033 cvar_t scratch2 = {0,"scratch2", "0", "unused cvar in quake, can be used by mods"};
2034 cvar_t scratch3 = {0, "scratch3", "0", "unused cvar in quake, can be used by mods"};
2035 cvar_t scratch4 = {0, "scratch4", "0", "unused cvar in quake, can be used by mods"};
2036 cvar_t savedgamecfg = {CVAR_SAVE, "savedgamecfg", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2037 cvar_t saved1 = {CVAR_SAVE, "saved1", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2038 cvar_t saved2 = {CVAR_SAVE, "saved2", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2039 cvar_t saved3 = {CVAR_SAVE, "saved3", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2040 cvar_t saved4 = {CVAR_SAVE, "saved4", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2041 cvar_t nehx00 = {0, "nehx00", "0", "nehahra data storage cvar (used in singleplayer)"};
2042 cvar_t nehx01 = {0, "nehx01", "0", "nehahra data storage cvar (used in singleplayer)"};
2043 cvar_t nehx02 = {0, "nehx02", "0", "nehahra data storage cvar (used in singleplayer)"};
2044 cvar_t nehx03 = {0, "nehx03", "0", "nehahra data storage cvar (used in singleplayer)"};
2045 cvar_t nehx04 = {0, "nehx04", "0", "nehahra data storage cvar (used in singleplayer)"};
2046 cvar_t nehx05 = {0, "nehx05", "0", "nehahra data storage cvar (used in singleplayer)"};
2047 cvar_t nehx06 = {0, "nehx06", "0", "nehahra data storage cvar (used in singleplayer)"};
2048 cvar_t nehx07 = {0, "nehx07", "0", "nehahra data storage cvar (used in singleplayer)"};
2049 cvar_t nehx08 = {0, "nehx08", "0", "nehahra data storage cvar (used in singleplayer)"};
2050 cvar_t nehx09 = {0, "nehx09", "0", "nehahra data storage cvar (used in singleplayer)"};
2051 cvar_t nehx10 = {0, "nehx10", "0", "nehahra data storage cvar (used in singleplayer)"};
2052 cvar_t nehx11 = {0, "nehx11", "0", "nehahra data storage cvar (used in singleplayer)"};
2053 cvar_t nehx12 = {0, "nehx12", "0", "nehahra data storage cvar (used in singleplayer)"};
2054 cvar_t nehx13 = {0, "nehx13", "0", "nehahra data storage cvar (used in singleplayer)"};
2055 cvar_t nehx14 = {0, "nehx14", "0", "nehahra data storage cvar (used in singleplayer)"};
2056 cvar_t nehx15 = {0, "nehx15", "0", "nehahra data storage cvar (used in singleplayer)"};
2057 cvar_t nehx16 = {0, "nehx16", "0", "nehahra data storage cvar (used in singleplayer)"};
2058 cvar_t nehx17 = {0, "nehx17", "0", "nehahra data storage cvar (used in singleplayer)"};
2059 cvar_t nehx18 = {0, "nehx18", "0", "nehahra data storage cvar (used in singleplayer)"};
2060 cvar_t nehx19 = {0, "nehx19", "0", "nehahra data storage cvar (used in singleplayer)"};
2061 cvar_t cutscene = {0, "cutscene", "1", "enables cutscenes in nehahra, can be used by other mods"};
2063 void SV_VM_Init(void)
2065 Cvar_RegisterVariable (&pr_checkextension);
2066 Cvar_RegisterVariable (&nomonsters);
2067 Cvar_RegisterVariable (&gamecfg);
2068 Cvar_RegisterVariable (&scratch1);
2069 Cvar_RegisterVariable (&scratch2);
2070 Cvar_RegisterVariable (&scratch3);
2071 Cvar_RegisterVariable (&scratch4);
2072 Cvar_RegisterVariable (&savedgamecfg);
2073 Cvar_RegisterVariable (&saved1);
2074 Cvar_RegisterVariable (&saved2);
2075 Cvar_RegisterVariable (&saved3);
2076 Cvar_RegisterVariable (&saved4);
2077 // LordHavoc: Nehahra uses these to pass data around cutscene demos
2078 if (gamemode == GAME_NEHAHRA)
2080 Cvar_RegisterVariable (&nehx00);
2081 Cvar_RegisterVariable (&nehx01);
2082 Cvar_RegisterVariable (&nehx02);
2083 Cvar_RegisterVariable (&nehx03);
2084 Cvar_RegisterVariable (&nehx04);
2085 Cvar_RegisterVariable (&nehx05);
2086 Cvar_RegisterVariable (&nehx06);
2087 Cvar_RegisterVariable (&nehx07);
2088 Cvar_RegisterVariable (&nehx08);
2089 Cvar_RegisterVariable (&nehx09);
2090 Cvar_RegisterVariable (&nehx10);
2091 Cvar_RegisterVariable (&nehx11);
2092 Cvar_RegisterVariable (&nehx12);
2093 Cvar_RegisterVariable (&nehx13);
2094 Cvar_RegisterVariable (&nehx14);
2095 Cvar_RegisterVariable (&nehx15);
2096 Cvar_RegisterVariable (&nehx16);
2097 Cvar_RegisterVariable (&nehx17);
2098 Cvar_RegisterVariable (&nehx18);
2099 Cvar_RegisterVariable (&nehx19);
2101 Cvar_RegisterVariable (&cutscene); // for Nehahra but useful to other mods as well
2104 // LordHavoc: in an effort to eliminate time wasted on GetEdictFieldValue... these are defined as externs in progs.h
2121 int eval_buttonchat;
2123 int eval_glow_trail;
2124 int eval_glow_color;
2128 int eval_renderamt; // HalfLife support
2129 int eval_rendermode; // HalfLife support
2130 int eval_fullbright;
2131 int eval_ammo_shells1;
2132 int eval_ammo_nails1;
2133 int eval_ammo_lava_nails;
2134 int eval_ammo_rockets1;
2135 int eval_ammo_multi_rockets;
2136 int eval_ammo_cells1;
2137 int eval_ammo_plasma;
2138 int eval_idealpitch;
2139 int eval_pitch_speed;
2140 int eval_viewmodelforclient;
2141 int eval_nodrawtoclient;
2142 int eval_exteriormodeltoclient;
2143 int eval_drawonlytoclient;
2147 int eval_punchvector;
2149 int eval_clientcolors;
2150 int eval_tag_entity;
2156 int eval_cursor_active;
2157 int eval_cursor_screen;
2158 int eval_cursor_trace_start;
2159 int eval_cursor_trace_endpos;
2160 int eval_cursor_trace_ent;
2162 int eval_playermodel;
2163 int eval_playerskin;
2164 int eval_SendEntity;
2166 int eval_customizeentityforclient;
2167 int eval_dphitcontentsmask;
2169 int gval_trace_dpstartcontents;
2170 int gval_trace_dphitcontents;
2171 int gval_trace_dphitq3surfaceflags;
2172 int gval_trace_dphittexturename;
2174 mfunction_t *SV_PlayerPhysicsQC;
2175 mfunction_t *EndFrameQC;
2176 //KrimZon - SERVER COMMANDS IN QUAKEC
2177 mfunction_t *SV_ParseClientCommandQC;
2179 ddef_t *PRVM_ED_FindGlobal(const char *name);
2181 void SV_VM_FindEdictFieldOffsets(void)
2183 eval_gravity = PRVM_ED_FindFieldOffset("gravity");
2184 eval_button3 = PRVM_ED_FindFieldOffset("button3");
2185 eval_button4 = PRVM_ED_FindFieldOffset("button4");
2186 eval_button5 = PRVM_ED_FindFieldOffset("button5");
2187 eval_button6 = PRVM_ED_FindFieldOffset("button6");
2188 eval_button7 = PRVM_ED_FindFieldOffset("button7");
2189 eval_button8 = PRVM_ED_FindFieldOffset("button8");
2190 eval_button9 = PRVM_ED_FindFieldOffset("button9");
2191 eval_button10 = PRVM_ED_FindFieldOffset("button10");
2192 eval_button11 = PRVM_ED_FindFieldOffset("button11");
2193 eval_button12 = PRVM_ED_FindFieldOffset("button12");
2194 eval_button13 = PRVM_ED_FindFieldOffset("button13");
2195 eval_button14 = PRVM_ED_FindFieldOffset("button14");
2196 eval_button15 = PRVM_ED_FindFieldOffset("button15");
2197 eval_button16 = PRVM_ED_FindFieldOffset("button16");
2198 eval_buttonuse = PRVM_ED_FindFieldOffset("buttonuse");
2199 eval_buttonchat = PRVM_ED_FindFieldOffset("buttonchat");
2200 eval_glow_size = PRVM_ED_FindFieldOffset("glow_size");
2201 eval_glow_trail = PRVM_ED_FindFieldOffset("glow_trail");
2202 eval_glow_color = PRVM_ED_FindFieldOffset("glow_color");
2203 eval_items2 = PRVM_ED_FindFieldOffset("items2");
2204 eval_scale = PRVM_ED_FindFieldOffset("scale");
2205 eval_alpha = PRVM_ED_FindFieldOffset("alpha");
2206 eval_renderamt = PRVM_ED_FindFieldOffset("renderamt"); // HalfLife support
2207 eval_rendermode = PRVM_ED_FindFieldOffset("rendermode"); // HalfLife support
2208 eval_fullbright = PRVM_ED_FindFieldOffset("fullbright");
2209 eval_ammo_shells1 = PRVM_ED_FindFieldOffset("ammo_shells1");
2210 eval_ammo_nails1 = PRVM_ED_FindFieldOffset("ammo_nails1");
2211 eval_ammo_lava_nails = PRVM_ED_FindFieldOffset("ammo_lava_nails");
2212 eval_ammo_rockets1 = PRVM_ED_FindFieldOffset("ammo_rockets1");
2213 eval_ammo_multi_rockets = PRVM_ED_FindFieldOffset("ammo_multi_rockets");
2214 eval_ammo_cells1 = PRVM_ED_FindFieldOffset("ammo_cells1");
2215 eval_ammo_plasma = PRVM_ED_FindFieldOffset("ammo_plasma");
2216 eval_idealpitch = PRVM_ED_FindFieldOffset("idealpitch");
2217 eval_pitch_speed = PRVM_ED_FindFieldOffset("pitch_speed");
2218 eval_viewmodelforclient = PRVM_ED_FindFieldOffset("viewmodelforclient");
2219 eval_nodrawtoclient = PRVM_ED_FindFieldOffset("nodrawtoclient");
2220 eval_exteriormodeltoclient = PRVM_ED_FindFieldOffset("exteriormodeltoclient");
2221 eval_drawonlytoclient = PRVM_ED_FindFieldOffset("drawonlytoclient");
2222 eval_ping = PRVM_ED_FindFieldOffset("ping");
2223 eval_movement = PRVM_ED_FindFieldOffset("movement");
2224 eval_pmodel = PRVM_ED_FindFieldOffset("pmodel");
2225 eval_punchvector = PRVM_ED_FindFieldOffset("punchvector");
2226 eval_viewzoom = PRVM_ED_FindFieldOffset("viewzoom");
2227 eval_clientcolors = PRVM_ED_FindFieldOffset("clientcolors");
2228 eval_tag_entity = PRVM_ED_FindFieldOffset("tag_entity");
2229 eval_tag_index = PRVM_ED_FindFieldOffset("tag_index");
2230 eval_light_lev = PRVM_ED_FindFieldOffset("light_lev");
2231 eval_color = PRVM_ED_FindFieldOffset("color");
2232 eval_style = PRVM_ED_FindFieldOffset("style");
2233 eval_pflags = PRVM_ED_FindFieldOffset("pflags");
2234 eval_cursor_active = PRVM_ED_FindFieldOffset("cursor_active");
2235 eval_cursor_screen = PRVM_ED_FindFieldOffset("cursor_screen");
2236 eval_cursor_trace_start = PRVM_ED_FindFieldOffset("cursor_trace_start");
2237 eval_cursor_trace_endpos = PRVM_ED_FindFieldOffset("cursor_trace_endpos");
2238 eval_cursor_trace_ent = PRVM_ED_FindFieldOffset("cursor_trace_ent");
2239 eval_colormod = PRVM_ED_FindFieldOffset("colormod");
2240 eval_playermodel = PRVM_ED_FindFieldOffset("playermodel");
2241 eval_playerskin = PRVM_ED_FindFieldOffset("playerskin");
2242 eval_SendEntity = PRVM_ED_FindFieldOffset("SendEntity");
2243 eval_Version = PRVM_ED_FindFieldOffset("Version");
2244 eval_customizeentityforclient = PRVM_ED_FindFieldOffset("customizeentityforclient");
2245 eval_dphitcontentsmask = PRVM_ED_FindFieldOffset("dphitcontentsmask");
2247 // LordHavoc: allowing QuakeC to override the player movement code
2248 SV_PlayerPhysicsQC = PRVM_ED_FindFunction ("SV_PlayerPhysics");
2249 // LordHavoc: support for endframe
2250 EndFrameQC = PRVM_ED_FindFunction ("EndFrame");
2251 //KrimZon - SERVER COMMANDS IN QUAKEC
2252 SV_ParseClientCommandQC = PRVM_ED_FindFunction ("SV_ParseClientCommand");
2254 //[515]: init stufftext string (it is sent before svc_serverinfo)
2255 if(PRVM_ED_FindGlobal("SV_InitCmd") && PRVM_ED_FindGlobal("SV_InitCmd")->type & ev_string)
2256 SV_InitCmd = PRVM_G_STRING(PRVM_ED_FindGlobal("SV_InitCmd")->ofs);
2260 gval_trace_dpstartcontents = PRVM_ED_FindGlobalOffset("trace_dpstartcontents");
2261 gval_trace_dphitcontents = PRVM_ED_FindGlobalOffset("trace_dphitcontents");
2262 gval_trace_dphitq3surfaceflags = PRVM_ED_FindGlobalOffset("trace_dphitq3surfaceflags");
2263 gval_trace_dphittexturename = PRVM_ED_FindGlobalOffset("trace_dphittexturename");
2266 #define REQFIELDS (sizeof(reqfields) / sizeof(prvm_required_field_t))
2268 prvm_required_field_t reqfields[] =
2270 {ev_entity, "cursor_trace_ent"},
2271 {ev_entity, "drawonlytoclient"},
2272 {ev_entity, "exteriormodeltoclient"},
2273 {ev_entity, "nodrawtoclient"},
2274 {ev_entity, "tag_entity"},
2275 {ev_entity, "viewmodelforclient"},
2276 {ev_float, "alpha"},
2277 {ev_float, "ammo_cells1"},
2278 {ev_float, "ammo_lava_nails"},
2279 {ev_float, "ammo_multi_rockets"},
2280 {ev_float, "ammo_nails1"},
2281 {ev_float, "ammo_plasma"},
2282 {ev_float, "ammo_rockets1"},
2283 {ev_float, "ammo_shells1"},
2284 {ev_float, "button3"},
2285 {ev_float, "button4"},
2286 {ev_float, "button5"},
2287 {ev_float, "button6"},
2288 {ev_float, "button7"},
2289 {ev_float, "button8"},
2290 {ev_float, "button9"},
2291 {ev_float, "button10"},
2292 {ev_float, "button11"},
2293 {ev_float, "button12"},
2294 {ev_float, "button13"},
2295 {ev_float, "button14"},
2296 {ev_float, "button15"},
2297 {ev_float, "button16"},
2298 {ev_float, "buttonchat"},
2299 {ev_float, "buttonuse"},
2300 {ev_float, "clientcolors"},
2301 {ev_float, "cursor_active"},
2302 {ev_float, "fullbright"},
2303 {ev_float, "glow_color"},
2304 {ev_float, "glow_size"},
2305 {ev_float, "glow_trail"},
2306 {ev_float, "gravity"},
2307 {ev_float, "idealpitch"},
2308 {ev_float, "items2"},
2309 {ev_float, "light_lev"},
2310 {ev_float, "pflags"},
2312 {ev_float, "pitch_speed"},
2313 {ev_float, "pmodel"},
2314 {ev_float, "renderamt"}, // HalfLife support
2315 {ev_float, "rendermode"}, // HalfLife support
2316 {ev_float, "scale"},
2317 {ev_float, "style"},
2318 {ev_float, "tag_index"},
2319 {ev_float, "Version"},
2320 {ev_float, "viewzoom"},
2321 {ev_vector, "color"},
2322 {ev_vector, "colormod"},
2323 {ev_vector, "cursor_screen"},
2324 {ev_vector, "cursor_trace_endpos"},
2325 {ev_vector, "cursor_trace_start"},
2326 {ev_vector, "movement"},
2327 {ev_vector, "punchvector"},
2328 {ev_string, "playermodel"},
2329 {ev_string, "playerskin"},
2330 {ev_function, "SendEntity"},
2331 {ev_function, "customizeentityforclient"},
2334 void SV_VM_Setup(void)
2337 PRVM_InitProg( PRVM_SERVERPROG );
2339 // allocate the mempools
2340 prog->progs_mempool = Mem_AllocPool("Server Progs", 0, NULL);
2341 prog->builtins = vm_sv_builtins;
2342 prog->numbuiltins = vm_sv_numbuiltins;
2343 prog->headercrc = PROGHEADER_CRC;
2344 prog->max_edicts = 512;
2345 prog->limit_edicts = MAX_EDICTS;
2346 prog->reserved_edicts = svs.maxclients;
2347 prog->edictprivate_size = sizeof(edict_engineprivate_t);
2348 prog->name = "server";
2349 prog->extensionstring = vm_sv_extensions;
2350 prog->loadintoworld = true;
2352 prog->begin_increase_edicts = SV_VM_CB_BeginIncreaseEdicts;
2353 prog->end_increase_edicts = SV_VM_CB_EndIncreaseEdicts;
2354 prog->init_edict = SV_VM_CB_InitEdict;
2355 prog->free_edict = SV_VM_CB_FreeEdict;
2356 prog->count_edicts = SV_VM_CB_CountEdicts;
2357 prog->load_edict = SV_VM_CB_LoadEdict;
2358 prog->init_cmd = VM_SV_Cmd_Init;
2359 prog->reset_cmd = VM_SV_Cmd_Reset;
2360 prog->error_cmd = Host_Error;
2362 // TODO: add a requiredfuncs list (ask LH if this is necessary at all)
2363 PRVM_LoadProgs( sv_progs.string, 0, NULL, REQFIELDS, reqfields );
2364 SV_VM_FindEdictFieldOffsets();
2366 VM_AutoSentStats_Clear();//[515]: csqc
2367 EntityFrameCSQC_ClearVersions();//[515]: csqc
2372 void SV_VM_Begin(void)
2375 PRVM_SetProg( PRVM_SERVERPROG );
2377 *prog->time = (float) sv.time;
2380 void SV_VM_End(void)