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;
60 extern cvar_t sv_clmovement_waitforinput;
65 mempool_t *sv_mempool = NULL;
67 //============================================================================
69 extern void SV_Phys_Init (void);
70 extern void SV_World_Init (void);
71 static void SV_SaveEntFile_f(void);
80 Cmd_AddCommand("sv_saveentfile", SV_SaveEntFile_f, "save map entities to .ent file (to allow external editing)");
81 Cvar_RegisterVariable (&sv_maxvelocity);
82 Cvar_RegisterVariable (&sv_gravity);
83 Cvar_RegisterVariable (&sv_friction);
84 Cvar_RegisterVariable (&sv_waterfriction);
85 Cvar_RegisterVariable (&sv_edgefriction);
86 Cvar_RegisterVariable (&sv_stopspeed);
87 Cvar_RegisterVariable (&sv_maxspeed);
88 Cvar_RegisterVariable (&sv_maxairspeed);
89 Cvar_RegisterVariable (&sv_accelerate);
90 Cvar_RegisterVariable (&sv_airaccelerate);
91 Cvar_RegisterVariable (&sv_wateraccelerate);
92 Cvar_RegisterVariable (&sv_clmovement_enable);
93 Cvar_RegisterVariable (&sv_clmovement_minping);
94 Cvar_RegisterVariable (&sv_clmovement_minping_disabletime);
95 Cvar_RegisterVariable (&sv_clmovement_waitforinput);
96 Cvar_RegisterVariable (&sv_idealpitchscale);
97 Cvar_RegisterVariable (&sv_aim);
98 Cvar_RegisterVariable (&sv_nostep);
99 Cvar_RegisterVariable (&sv_cullentities_pvs);
100 Cvar_RegisterVariable (&sv_cullentities_trace);
101 Cvar_RegisterVariable (&sv_cullentities_stats);
102 Cvar_RegisterVariable (&sv_entpatch);
103 Cvar_RegisterVariable (&sv_gameplayfix_grenadebouncedownslopes);
104 Cvar_RegisterVariable (&sv_gameplayfix_noairborncorpse);
105 Cvar_RegisterVariable (&sv_gameplayfix_stepdown);
106 Cvar_RegisterVariable (&sv_gameplayfix_stepwhilejumping);
107 Cvar_RegisterVariable (&sv_gameplayfix_swiminbmodels);
108 Cvar_RegisterVariable (&sv_gameplayfix_setmodelrealbox);
109 Cvar_RegisterVariable (&sv_gameplayfix_blowupfallenzombies);
110 Cvar_RegisterVariable (&sv_gameplayfix_findradiusdistancetobox);
111 Cvar_RegisterVariable (&sv_gameplayfix_qwplayerphysics);
112 Cvar_RegisterVariable (&sv_protocolname);
113 Cvar_RegisterVariable (&sv_ratelimitlocalplayer);
114 Cvar_RegisterVariable (&sv_maxrate);
115 Cvar_RegisterVariable (&sv_progs);
121 sv_mempool = Mem_AllocPool("server", 0, NULL);
124 static void SV_SaveEntFile_f(void)
126 char basename[MAX_QPATH];
127 if (!sv.active || !sv.worldmodel)
129 Con_Print("Not running a server\n");
132 FS_StripExtension(sv.worldmodel->name, basename, sizeof(basename));
133 FS_WriteFile(va("%s.ent", basename), sv.worldmodel->brush.entities, (fs_offset_t)strlen(sv.worldmodel->brush.entities));
138 =============================================================================
142 =============================================================================
149 Make sure the event gets sent to all clients
152 void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count)
156 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-18)
158 MSG_WriteByte (&sv.datagram, svc_particle);
159 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
160 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
161 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
162 for (i=0 ; i<3 ; i++)
163 MSG_WriteChar (&sv.datagram, (int)bound(-128, dir[i]*16, 127));
164 MSG_WriteByte (&sv.datagram, count);
165 MSG_WriteByte (&sv.datagram, color);
172 Make sure the event gets sent to all clients
175 void SV_StartEffect (vec3_t org, int modelindex, int startframe, int framecount, int framerate)
177 if (modelindex >= 256 || startframe >= 256)
179 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-19)
181 MSG_WriteByte (&sv.datagram, svc_effect2);
182 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
183 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
184 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
185 MSG_WriteShort (&sv.datagram, modelindex);
186 MSG_WriteShort (&sv.datagram, startframe);
187 MSG_WriteByte (&sv.datagram, framecount);
188 MSG_WriteByte (&sv.datagram, framerate);
192 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-17)
194 MSG_WriteByte (&sv.datagram, svc_effect);
195 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
196 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
197 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
198 MSG_WriteByte (&sv.datagram, modelindex);
199 MSG_WriteByte (&sv.datagram, startframe);
200 MSG_WriteByte (&sv.datagram, framecount);
201 MSG_WriteByte (&sv.datagram, framerate);
209 Each entity can have eight independant sound sources, like voice,
212 Channel 0 is an auto-allocate channel, the others override anything
213 already running on that entity/channel pair.
215 An attenuation of 0 will play full volume everywhere in the level.
216 Larger attenuations will drop off. (max 4 attenuation)
220 void SV_StartSound (prvm_edict_t *entity, int channel, const char *sample, int volume, float attenuation)
222 int sound_num, field_mask, i, ent;
224 if (volume < 0 || volume > 255)
226 Con_Printf ("SV_StartSound: volume = %i\n", volume);
230 if (attenuation < 0 || attenuation > 4)
232 Con_Printf ("SV_StartSound: attenuation = %f\n", attenuation);
236 if (channel < 0 || channel > 7)
238 Con_Printf ("SV_StartSound: channel = %i\n", channel);
242 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-21)
245 // find precache number for sound
246 sound_num = SV_SoundIndex(sample, 1);
250 ent = PRVM_NUM_FOR_EDICT(entity);
253 if (volume != DEFAULT_SOUND_PACKET_VOLUME)
254 field_mask |= SND_VOLUME;
255 if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
256 field_mask |= SND_ATTENUATION;
258 field_mask |= SND_LARGEENTITY;
259 if (sound_num >= 256 || channel >= 8)
260 field_mask |= SND_LARGESOUND;
262 // directed messages go only to the entity they are targeted on
263 MSG_WriteByte (&sv.datagram, svc_sound);
264 MSG_WriteByte (&sv.datagram, field_mask);
265 if (field_mask & SND_VOLUME)
266 MSG_WriteByte (&sv.datagram, volume);
267 if (field_mask & SND_ATTENUATION)
268 MSG_WriteByte (&sv.datagram, (int)(attenuation*64));
269 if (field_mask & SND_LARGEENTITY)
271 MSG_WriteShort (&sv.datagram, ent);
272 MSG_WriteByte (&sv.datagram, channel);
275 MSG_WriteShort (&sv.datagram, (ent<<3) | channel);
276 if (field_mask & SND_LARGESOUND)
277 MSG_WriteShort (&sv.datagram, sound_num);
279 MSG_WriteByte (&sv.datagram, sound_num);
280 for (i = 0;i < 3;i++)
281 MSG_WriteCoord (&sv.datagram, entity->fields.server->origin[i]+0.5*(entity->fields.server->mins[i]+entity->fields.server->maxs[i]), sv.protocol);
285 ==============================================================================
289 ==============================================================================
292 static const char *SV_InitCmd; //[515]: svprogs able to send cmd to client on connect
293 extern qboolean csqc_loaded;
298 Sends the first message from the server to a connected client.
299 This will be sent on the initial connection and upon each server load.
302 void SV_SendServerinfo (client_t *client)
307 // we know that this client has a netconnection and thus is not a bot
309 // edicts get reallocated on level changes, so we need to update it here
310 client->edict = PRVM_EDICT_NUM((client - svs.clients) + 1);
312 // clear cached stuff that depends on the level
313 client->weaponmodel[0] = 0;
314 client->weaponmodelindex = 0;
316 // LordHavoc: clear entityframe tracking
317 client->latestframenum = 0;
319 if (client->entitydatabase)
320 EntityFrame_FreeDatabase(client->entitydatabase);
321 if (client->entitydatabase4)
322 EntityFrame4_FreeDatabase(client->entitydatabase4);
323 if (client->entitydatabase5)
324 EntityFrame5_FreeDatabase(client->entitydatabase5);
326 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
328 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3)
329 client->entitydatabase = EntityFrame_AllocDatabase(sv_mempool);
330 else if (sv.protocol == PROTOCOL_DARKPLACES4)
331 client->entitydatabase4 = EntityFrame4_AllocDatabase(sv_mempool);
333 client->entitydatabase5 = EntityFrame5_AllocDatabase(sv_mempool);
336 SZ_Clear (&client->netconnection->message);
337 MSG_WriteByte (&client->netconnection->message, svc_print);
338 dpsnprintf (message, sizeof (message), "\nServer: %s build %s (progs %i crc)", gamename, buildstring, prog->filecrc);
339 MSG_WriteString (&client->netconnection->message,message);
341 // FIXME: LordHavoc: this does not work on dedicated servers, needs fixing.
342 //[515]: init csprogs according to version of svprogs, check the crc, etc.
343 if(csqc_loaded && (cls.state == ca_dedicated || PRVM_NUM_FOR_EDICT(client->edict) != 1))
345 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
347 MSG_WriteString (&client->netconnection->message, va("csqc_progcrc %i;%s\n", csqc_progcrc.integer, SV_InitCmd));
349 MSG_WriteString (&client->netconnection->message, va("csqc_progcrc %i\n", csqc_progcrc.integer));
352 MSG_WriteByte (&client->netconnection->message, svc_serverinfo);
353 MSG_WriteLong (&client->netconnection->message, Protocol_NumberForEnum(sv.protocol));
354 MSG_WriteByte (&client->netconnection->message, svs.maxclients);
356 if (!coop.integer && deathmatch.integer)
357 MSG_WriteByte (&client->netconnection->message, GAME_DEATHMATCH);
359 MSG_WriteByte (&client->netconnection->message, GAME_COOP);
361 MSG_WriteString (&client->netconnection->message,PRVM_GetString(prog->edicts->fields.server->message));
363 for (i = 1;i < MAX_MODELS && sv.model_precache[i][0];i++)
364 MSG_WriteString (&client->netconnection->message, sv.model_precache[i]);
365 MSG_WriteByte (&client->netconnection->message, 0);
367 for (i = 1;i < MAX_SOUNDS && sv.sound_precache[i][0];i++)
368 MSG_WriteString (&client->netconnection->message, sv.sound_precache[i]);
369 MSG_WriteByte (&client->netconnection->message, 0);
372 MSG_WriteByte (&client->netconnection->message, svc_cdtrack);
373 MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
374 MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
377 MSG_WriteByte (&client->netconnection->message, svc_setview);
378 MSG_WriteShort (&client->netconnection->message, PRVM_NUM_FOR_EDICT(client->edict));
380 MSG_WriteByte (&client->netconnection->message, svc_signonnum);
381 MSG_WriteByte (&client->netconnection->message, 1);
383 client->spawned = false; // need prespawn, spawn, etc
390 Initializes a client_t for a new net connection. This will only be called
391 once for a player each game, not once for each level change.
394 void SV_ConnectClient (int clientnum, netconn_t *netconnection)
398 float spawn_parms[NUM_SPAWN_PARMS];
400 client = svs.clients + clientnum;
402 if(netconnection)//[515]: bots don't play with csqc =)
403 EntityFrameCSQC_InitClientVersions(clientnum, false);
405 // set up the client_t
407 memcpy (spawn_parms, client->spawn_parms, sizeof(spawn_parms));
408 memset (client, 0, sizeof(*client));
409 client->active = true;
410 client->netconnection = netconnection;
412 Con_DPrintf("Client %s connected\n", client->netconnection ? client->netconnection->address : "botclient");
414 strcpy(client->name, "unconnected");
415 strcpy(client->old_name, "unconnected");
416 client->spawned = false;
417 client->edict = PRVM_EDICT_NUM(clientnum+1);
418 if (client->netconnection)
419 client->netconnection->message.allowoverflow = true; // we can catch it
420 // updated by receiving "rate" command from client
421 client->rate = NET_MINRATE;
422 // no limits for local player
423 if (client->netconnection && LHNETADDRESS_GetAddressType(&client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP)
424 client->rate = 1000000000;
425 client->connecttime = realtime;
428 memcpy (client->spawn_parms, spawn_parms, sizeof(spawn_parms));
431 // call the progs to get default spawn parms for the new client
432 // set self to world to intentionally cause errors with broken SetNewParms code in some mods
433 prog->globals.server->self = 0;
434 PRVM_ExecuteProgram (prog->globals.server->SetNewParms, "QC function SetNewParms is missing");
435 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
436 client->spawn_parms[i] = (&prog->globals.server->parm1)[i];
438 // set up the entity for this client (including .colormap, .team, etc)
439 PRVM_ED_ClearEdict(client->edict);
442 // don't call SendServerinfo for a fresh botclient because its fields have
443 // not been set up by the qc yet
444 if (client->netconnection)
445 SV_SendServerinfo (client);
447 client->spawned = true;
452 ===============================================================================
456 ===============================================================================
465 void SV_ClearDatagram (void)
467 SZ_Clear (&sv.datagram);
471 =============================================================================
473 The PVS must include a small area around the client to allow head bobbing
474 or other small motion on the client side. Otherwise, a bob might cause an
475 entity that should be visible to not show up, especially when the bob
478 =============================================================================
481 int sv_writeentitiestoclient_pvsbytes;
482 unsigned char sv_writeentitiestoclient_pvs[MAX_MAP_LEAFS/8];
484 static int numsendentities;
485 static entity_state_t sendentities[MAX_EDICTS];
486 static entity_state_t *sendentitiesindex[MAX_EDICTS];
488 qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *cs, int e)
491 unsigned int modelindex, effects, flags, glowsize, lightstyle, lightpflags, light[4], specialvisibilityradius;
492 unsigned int customizeentityforclient;
494 vec3_t cullmins, cullmaxs;
498 // EF_NODRAW prevents sending for any reason except for your own
499 // client, so we must keep all clients in this superset
500 effects = (unsigned)ent->fields.server->effects;
502 // we can omit invisible entities with no effects that are not clients
503 // LordHavoc: this could kill tags attached to an invisible entity, I
504 // just hope we never have to support that case
505 i = (int)ent->fields.server->modelindex;
506 modelindex = (i >= 1 && i < MAX_MODELS && *PRVM_GetString(ent->fields.server->model)) ? i : 0;
509 i = (int)(PRVM_GETEDICTFIELDVALUE(ent, eval_glow_size)->_float * 0.25f);
510 glowsize = (unsigned char)bound(0, i, 255);
511 if (PRVM_GETEDICTFIELDVALUE(ent, eval_glow_trail)->_float)
512 flags |= RENDER_GLOWTRAIL;
514 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[0]*256;
515 light[0] = (unsigned short)bound(0, f, 65535);
516 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[1]*256;
517 light[1] = (unsigned short)bound(0, f, 65535);
518 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[2]*256;
519 light[2] = (unsigned short)bound(0, f, 65535);
520 f = PRVM_GETEDICTFIELDVALUE(ent, eval_light_lev)->_float;
521 light[3] = (unsigned short)bound(0, f, 65535);
522 lightstyle = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_style)->_float;
523 lightpflags = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_pflags)->_float;
525 if (gamemode == GAME_TENEBRAE)
527 // tenebrae's EF_FULLDYNAMIC conflicts with Q2's EF_NODRAW
531 lightpflags |= PFLAGS_FULLDYNAMIC;
533 // tenebrae's EF_GREEN conflicts with DP's EF_ADDITIVE
537 light[0] = (int)(0.2*256);
538 light[1] = (int)(1.0*256);
539 light[2] = (int)(0.2*256);
541 lightpflags |= PFLAGS_FULLDYNAMIC;
545 specialvisibilityradius = 0;
546 if (lightpflags & PFLAGS_FULLDYNAMIC)
547 specialvisibilityradius = max(specialvisibilityradius, light[3]);
549 specialvisibilityradius = max(specialvisibilityradius, glowsize * 4);
550 if (flags & RENDER_GLOWTRAIL)
551 specialvisibilityradius = max(specialvisibilityradius, 100);
552 if (effects & (EF_BRIGHTFIELD | EF_MUZZLEFLASH | EF_BRIGHTLIGHT | EF_DIMLIGHT | EF_RED | EF_BLUE | EF_FLAME | EF_STARDUST))
554 if (effects & EF_BRIGHTFIELD)
555 specialvisibilityradius = max(specialvisibilityradius, 80);
556 if (effects & EF_MUZZLEFLASH)
557 specialvisibilityradius = max(specialvisibilityradius, 100);
558 if (effects & EF_BRIGHTLIGHT)
559 specialvisibilityradius = max(specialvisibilityradius, 400);
560 if (effects & EF_DIMLIGHT)
561 specialvisibilityradius = max(specialvisibilityradius, 200);
562 if (effects & EF_RED)
563 specialvisibilityradius = max(specialvisibilityradius, 200);
564 if (effects & EF_BLUE)
565 specialvisibilityradius = max(specialvisibilityradius, 200);
566 if (effects & EF_FLAME)
567 specialvisibilityradius = max(specialvisibilityradius, 250);
568 if (effects & EF_STARDUST)
569 specialvisibilityradius = max(specialvisibilityradius, 100);
572 // early culling checks
573 // (final culling is done by SV_MarkWriteEntityStateToClient)
574 customizeentityforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_customizeentityforclient)->function;
575 if (!customizeentityforclient)
577 if (e > svs.maxclients && (!modelindex && !specialvisibilityradius))
579 // this 2 billion unit check is actually to detect NAN origins
580 // (we really don't want to send those)
581 if (VectorLength2(ent->fields.server->origin) > 2000000000.0*2000000000.0)
589 VectorCopy(ent->fields.server->origin, cs->origin);
590 VectorCopy(ent->fields.server->angles, cs->angles);
592 cs->effects = effects;
593 cs->colormap = (unsigned)ent->fields.server->colormap;
594 cs->modelindex = modelindex;
595 cs->skin = (unsigned)ent->fields.server->skin;
596 cs->frame = (unsigned)ent->fields.server->frame;
597 cs->viewmodelforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)->edict;
598 cs->exteriormodelforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_exteriormodeltoclient)->edict;
599 cs->nodrawtoclient = PRVM_GETEDICTFIELDVALUE(ent, eval_nodrawtoclient)->edict;
600 cs->drawonlytoclient = PRVM_GETEDICTFIELDVALUE(ent, eval_drawonlytoclient)->edict;
601 cs->customizeentityforclient = customizeentityforclient;
602 cs->tagentity = PRVM_GETEDICTFIELDVALUE(ent, eval_tag_entity)->edict;
603 cs->tagindex = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_tag_index)->_float;
604 cs->glowsize = glowsize;
606 // don't need to init cs->colormod because the defaultstate did that for us
607 //cs->colormod[0] = cs->colormod[1] = cs->colormod[2] = 32;
608 val = PRVM_GETEDICTFIELDVALUE(ent, eval_colormod);
609 if (val->vector[0] || val->vector[1] || val->vector[2])
611 i = (int)(val->vector[0] * 32.0f);cs->colormod[0] = bound(0, i, 255);
612 i = (int)(val->vector[1] * 32.0f);cs->colormod[1] = bound(0, i, 255);
613 i = (int)(val->vector[2] * 32.0f);cs->colormod[2] = bound(0, i, 255);
616 cs->modelindex = modelindex;
619 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_alpha)->_float * 255.0f);
623 cs->alpha = (unsigned char)bound(0, i, 255);
626 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_renderamt)->_float);
630 cs->alpha = (unsigned char)bound(0, i, 255);
634 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_scale)->_float * 16.0f);
638 cs->scale = (unsigned char)bound(0, i, 255);
642 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_glow_color)->_float);
644 cs->glowcolor = (int)f;
646 if (PRVM_GETEDICTFIELDVALUE(ent, eval_fullbright)->_float)
647 cs->effects |= EF_FULLBRIGHT;
649 if (ent->fields.server->movetype == MOVETYPE_STEP)
650 cs->flags |= RENDER_STEP;
651 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)
652 cs->flags |= RENDER_LOWPRECISION;
653 if (ent->fields.server->colormap >= 1024)
654 cs->flags |= RENDER_COLORMAPPED;
655 if (cs->viewmodelforclient)
656 cs->flags |= RENDER_VIEWMODEL; // show relative to the view
658 cs->light[0] = light[0];
659 cs->light[1] = light[1];
660 cs->light[2] = light[2];
661 cs->light[3] = light[3];
662 cs->lightstyle = lightstyle;
663 cs->lightpflags = lightpflags;
665 cs->specialvisibilityradius = specialvisibilityradius;
667 // calculate the visible box of this entity (don't use the physics box
668 // as that is often smaller than a model, and would not count
669 // specialvisibilityradius)
670 if ((model = sv.models[modelindex]))
672 float scale = cs->scale * (1.0f / 16.0f);
673 if (cs->angles[0] || cs->angles[2]) // pitch and roll
675 VectorMA(cs->origin, scale, model->rotatedmins, cullmins);
676 VectorMA(cs->origin, scale, model->rotatedmaxs, cullmaxs);
678 else if (cs->angles[1])
680 VectorMA(cs->origin, scale, model->yawmins, cullmins);
681 VectorMA(cs->origin, scale, model->yawmaxs, cullmaxs);
685 VectorMA(cs->origin, scale, model->normalmins, cullmins);
686 VectorMA(cs->origin, scale, model->normalmaxs, cullmaxs);
691 // if there is no model (or it could not be loaded), use the physics box
692 VectorAdd(cs->origin, ent->fields.server->mins, cullmins);
693 VectorAdd(cs->origin, ent->fields.server->maxs, cullmaxs);
695 if (specialvisibilityradius)
697 cullmins[0] = min(cullmins[0], cs->origin[0] - specialvisibilityradius);
698 cullmins[1] = min(cullmins[1], cs->origin[1] - specialvisibilityradius);
699 cullmins[2] = min(cullmins[2], cs->origin[2] - specialvisibilityradius);
700 cullmaxs[0] = max(cullmaxs[0], cs->origin[0] + specialvisibilityradius);
701 cullmaxs[1] = max(cullmaxs[1], cs->origin[1] + specialvisibilityradius);
702 cullmaxs[2] = max(cullmaxs[2], cs->origin[2] + specialvisibilityradius);
704 if (!VectorCompare(cullmins, ent->priv.server->cullmins) || !VectorCompare(cullmaxs, ent->priv.server->cullmaxs))
706 VectorCopy(cullmins, ent->priv.server->cullmins);
707 VectorCopy(cullmaxs, ent->priv.server->cullmaxs);
708 ent->priv.server->pvs_numclusters = -1;
709 if (sv.worldmodel && sv.worldmodel->brush.FindBoxClusters)
711 i = sv.worldmodel->brush.FindBoxClusters(sv.worldmodel, cullmins, cullmaxs, MAX_ENTITYCLUSTERS, ent->priv.server->pvs_clusterlist);
712 if (i <= MAX_ENTITYCLUSTERS)
713 ent->priv.server->pvs_numclusters = i;
720 void SV_PrepareEntitiesForSending(void)
724 // send all entities that touch the pvs
726 sendentitiesindex[0] = NULL;
727 memset(sendentitiesindex, 0, prog->num_edicts * sizeof(entity_state_t *));
728 for (e = 1, ent = PRVM_NEXT_EDICT(prog->edicts);e < prog->num_edicts;e++, ent = PRVM_NEXT_EDICT(ent))
730 if (!ent->priv.server->free && SV_PrepareEntityForSending(ent, sendentities + numsendentities, e))
732 sendentitiesindex[e] = sendentities + numsendentities;
738 static int sententitiesmark = 0;
739 static int sententities[MAX_EDICTS];
740 static int sententitiesconsideration[MAX_EDICTS];
741 static int sv_writeentitiestoclient_culled_pvs;
742 static int sv_writeentitiestoclient_culled_trace;
743 static int sv_writeentitiestoclient_visibleentities;
744 static int sv_writeentitiestoclient_totalentities;
745 //static entity_frame_t sv_writeentitiestoclient_entityframe;
746 static int sv_writeentitiestoclient_clentnum;
747 static vec3_t sv_writeentitiestoclient_testeye;
748 static client_t *sv_writeentitiestoclient_client;
750 void SV_MarkWriteEntityStateToClient(entity_state_t *s)
757 if (sententitiesconsideration[s->number] == sententitiesmark)
759 sententitiesconsideration[s->number] = sententitiesmark;
760 sv_writeentitiestoclient_totalentities++;
762 if (s->customizeentityforclient)
764 prog->globals.server->self = s->number;
765 prog->globals.server->other = sv_writeentitiestoclient_clentnum;
766 PRVM_ExecuteProgram(s->customizeentityforclient, "customizeentityforclient: NULL function");
767 if(!PRVM_G_FLOAT(OFS_RETURN) || !SV_PrepareEntityForSending(PRVM_EDICT_NUM(s->number), s, s->number))
771 // never reject player
772 if (s->number != sv_writeentitiestoclient_clentnum)
774 // check various rejection conditions
775 if (s->nodrawtoclient == sv_writeentitiestoclient_clentnum)
777 if (s->drawonlytoclient && s->drawonlytoclient != sv_writeentitiestoclient_clentnum)
779 if (s->effects & EF_NODRAW)
781 // LordHavoc: only send entities with a model or important effects
782 if (!s->modelindex && s->specialvisibilityradius == 0)
785 // viewmodels don't have visibility checking
786 if (s->viewmodelforclient)
788 if (s->viewmodelforclient != sv_writeentitiestoclient_clentnum)
791 else if (s->tagentity)
793 // tag attached entities simply check their parent
794 if (!sendentitiesindex[s->tagentity])
796 SV_MarkWriteEntityStateToClient(sendentitiesindex[s->tagentity]);
797 if (sententities[s->tagentity] != sententitiesmark)
800 // always send world submodels in newer protocols because they don't
801 // generate much traffic (in old protocols they hog bandwidth)
802 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)))
804 // entity has survived every check so far, check if visible
805 ed = PRVM_EDICT_NUM(s->number);
807 // if not touching a visible leaf
808 if (sv_cullentities_pvs.integer && sv_writeentitiestoclient_pvsbytes)
810 if (ed->priv.server->pvs_numclusters < 0)
812 // entity too big for clusters list
813 if (sv.worldmodel && sv.worldmodel->brush.BoxTouchingPVS && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, sv_writeentitiestoclient_pvs, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
815 sv_writeentitiestoclient_culled_pvs++;
822 // check cached clusters list
823 for (i = 0;i < ed->priv.server->pvs_numclusters;i++)
824 if (CHECKPVSBIT(sv_writeentitiestoclient_pvs, ed->priv.server->pvs_clusterlist[i]))
826 if (i == ed->priv.server->pvs_numclusters)
828 sv_writeentitiestoclient_culled_pvs++;
834 // or not seen by random tracelines
835 if (sv_cullentities_trace.integer && !isbmodel)
837 // LordHavoc: test center first
838 testorigin[0] = (ed->priv.server->cullmins[0] + ed->priv.server->cullmaxs[0]) * 0.5f;
839 testorigin[1] = (ed->priv.server->cullmins[1] + ed->priv.server->cullmaxs[1]) * 0.5f;
840 testorigin[2] = (ed->priv.server->cullmins[2] + ed->priv.server->cullmaxs[2]) * 0.5f;
841 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
842 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
843 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
846 // LordHavoc: test random offsets, to maximize chance of detection
847 testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]);
848 testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]);
849 testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]);
850 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
851 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
852 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
855 if (s->specialvisibilityradius)
857 // LordHavoc: test random offsets, to maximize chance of detection
858 testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]);
859 testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]);
860 testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]);
861 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
862 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
863 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
867 if (realtime > sv_writeentitiestoclient_client->visibletime[s->number])
869 sv_writeentitiestoclient_culled_trace++;
876 // this just marks it for sending
877 // FIXME: it would be more efficient to send here, but the entity
878 // compressor isn't that flexible
879 sv_writeentitiestoclient_visibleentities++;
880 sententities[s->number] = sententitiesmark;
883 entity_state_t sendstates[MAX_EDICTS];
884 extern int csqc_clent;
886 void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t *msg, int *stats)
888 int i, numsendstates;
891 // if there isn't enough space to accomplish anything, skip it
892 if (msg->cursize + 25 > msg->maxsize)
895 sv_writeentitiestoclient_client = client;
897 sv_writeentitiestoclient_culled_pvs = 0;
898 sv_writeentitiestoclient_culled_trace = 0;
899 sv_writeentitiestoclient_visibleentities = 0;
900 sv_writeentitiestoclient_totalentities = 0;
902 // find the client's PVS
903 // the real place being tested from
904 VectorAdd(clent->fields.server->origin, clent->fields.server->view_ofs, sv_writeentitiestoclient_testeye);
905 sv_writeentitiestoclient_pvsbytes = 0;
906 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
907 sv_writeentitiestoclient_pvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, sv_writeentitiestoclient_testeye, 8, sv_writeentitiestoclient_pvs, sizeof(sv_writeentitiestoclient_pvs));
909 csqc_clent = sv_writeentitiestoclient_clentnum = PRVM_EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes
913 for (i = 0;i < numsendentities;i++)
914 SV_MarkWriteEntityStateToClient(sendentities + i);
917 for (i = 0;i < numsendentities;i++)
919 if (sententities[sendentities[i].number] == sententitiesmark)
921 s = &sendstates[numsendstates++];
922 *s = sendentities[i];
923 if (s->exteriormodelforclient && s->exteriormodelforclient == sv_writeentitiestoclient_clentnum)
924 s->flags |= RENDER_EXTERIORMODEL;
928 if (sv_cullentities_stats.integer)
929 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);
931 EntityFrameCSQC_WriteFrame(msg, numsendstates, sendstates);
933 if (client->entitydatabase5)
934 EntityFrame5_WriteFrame(msg, client->entitydatabase5, numsendstates, sendstates, client - svs.clients + 1, stats, client->movesequence);
935 else if (client->entitydatabase4)
936 EntityFrame4_WriteFrame(msg, client->entitydatabase4, numsendstates, sendstates);
937 else if (client->entitydatabase)
938 EntityFrame_WriteFrame(msg, client->entitydatabase, numsendstates, sendstates, client - svs.clients + 1);
940 EntityFrameQuake_WriteFrame(msg, numsendstates, sendstates);
949 void SV_CleanupEnts (void)
954 ent = PRVM_NEXT_EDICT(prog->edicts);
955 for (e=1 ; e<prog->num_edicts ; e++, ent = PRVM_NEXT_EDICT(ent))
956 ent->fields.server->effects = (int)ent->fields.server->effects & ~EF_MUZZLEFLASH;
961 SV_WriteClientdataToMessage
965 void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
977 // send a damage message
979 if (ent->fields.server->dmg_take || ent->fields.server->dmg_save)
981 other = PRVM_PROG_TO_EDICT(ent->fields.server->dmg_inflictor);
982 MSG_WriteByte (msg, svc_damage);
983 MSG_WriteByte (msg, (int)ent->fields.server->dmg_save);
984 MSG_WriteByte (msg, (int)ent->fields.server->dmg_take);
985 for (i=0 ; i<3 ; i++)
986 MSG_WriteCoord (msg, other->fields.server->origin[i] + 0.5*(other->fields.server->mins[i] + other->fields.server->maxs[i]), sv.protocol);
988 ent->fields.server->dmg_take = 0;
989 ent->fields.server->dmg_save = 0;
993 // send the current viewpos offset from the view entity
995 SV_SetIdealPitch (); // how much to look up / down ideally
997 // a fixangle might get lost in a dropped packet. Oh well.
998 if ( ent->fields.server->fixangle )
1000 MSG_WriteByte (msg, svc_setangle);
1001 for (i=0 ; i < 3 ; i++)
1002 MSG_WriteAngle (msg, ent->fields.server->angles[i], sv.protocol);
1003 ent->fields.server->fixangle = 0;
1006 // stuff the sigil bits into the high bits of items for sbar, or else
1008 val = PRVM_GETEDICTFIELDVALUE(ent, eval_items2);
1009 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
1010 items = (int)ent->fields.server->items | ((int)val->_float << 23);
1012 items = (int)ent->fields.server->items | ((int)prog->globals.server->serverflags << 28);
1014 VectorClear(punchvector);
1015 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_punchvector)))
1016 VectorCopy(val->vector, punchvector);
1018 // cache weapon model name and index in client struct to save time
1019 // (this search can be almost 1% of cpu time!)
1020 s = PRVM_GetString(ent->fields.server->weaponmodel);
1021 if (strcmp(s, client->weaponmodel))
1023 strlcpy(client->weaponmodel, s, sizeof(client->weaponmodel));
1024 client->weaponmodelindex = SV_ModelIndex(s, 1);
1028 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_viewzoom)))
1029 viewzoom = (int)(val->_float * 255.0f);
1035 if ((int)ent->fields.server->flags & FL_ONGROUND)
1036 bits |= SU_ONGROUND;
1037 if (ent->fields.server->waterlevel >= 2)
1039 if (ent->fields.server->idealpitch)
1040 bits |= SU_IDEALPITCH;
1042 for (i=0 ; i<3 ; i++)
1044 if (ent->fields.server->punchangle[i])
1045 bits |= (SU_PUNCH1<<i);
1046 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
1048 bits |= (SU_PUNCHVEC1<<i);
1049 if (ent->fields.server->velocity[i])
1050 bits |= (SU_VELOCITY1<<i);
1053 memset(stats, 0, sizeof(int[MAX_CL_STATS]));
1054 stats[STAT_VIEWHEIGHT] = (int)ent->fields.server->view_ofs[2];
1055 stats[STAT_ITEMS] = items;
1056 stats[STAT_WEAPONFRAME] = (int)ent->fields.server->weaponframe;
1057 stats[STAT_ARMOR] = (int)ent->fields.server->armorvalue;
1058 stats[STAT_WEAPON] = client->weaponmodelindex;
1059 stats[STAT_HEALTH] = (int)ent->fields.server->health;
1060 stats[STAT_AMMO] = (int)ent->fields.server->currentammo;
1061 stats[STAT_SHELLS] = (int)ent->fields.server->ammo_shells;
1062 stats[STAT_NAILS] = (int)ent->fields.server->ammo_nails;
1063 stats[STAT_ROCKETS] = (int)ent->fields.server->ammo_rockets;
1064 stats[STAT_CELLS] = (int)ent->fields.server->ammo_cells;
1065 stats[STAT_ACTIVEWEAPON] = (int)ent->fields.server->weapon;
1066 stats[STAT_VIEWZOOM] = viewzoom;
1067 // the QC bumps these itself by sending svc_'s, so we have to keep them
1068 // zero or they'll be corrected by the engine
1069 //stats[STAT_TOTALSECRETS] = prog->globals.server->total_secrets;
1070 //stats[STAT_TOTALMONSTERS] = prog->globals.server->total_monsters;
1071 //stats[STAT_SECRETS] = prog->globals.server->found_secrets;
1072 //stats[STAT_MONSTERS] = prog->globals.server->killed_monsters;
1074 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)
1076 if (stats[STAT_VIEWHEIGHT] != DEFAULT_VIEWHEIGHT) bits |= SU_VIEWHEIGHT;
1078 if (stats[STAT_WEAPONFRAME]) bits |= SU_WEAPONFRAME;
1079 if (stats[STAT_ARMOR]) bits |= SU_ARMOR;
1081 // FIXME: which protocols support this? does PROTOCOL_DARKPLACES3 support viewzoom?
1082 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
1083 if (viewzoom != 255)
1084 bits |= SU_VIEWZOOM;
1089 if (bits >= 16777216)
1093 MSG_WriteByte (msg, svc_clientdata);
1094 MSG_WriteShort (msg, bits);
1095 if (bits & SU_EXTEND1)
1096 MSG_WriteByte(msg, bits >> 16);
1097 if (bits & SU_EXTEND2)
1098 MSG_WriteByte(msg, bits >> 24);
1100 if (bits & SU_VIEWHEIGHT)
1101 MSG_WriteChar (msg, stats[STAT_VIEWHEIGHT]);
1103 if (bits & SU_IDEALPITCH)
1104 MSG_WriteChar (msg, (int)ent->fields.server->idealpitch);
1106 for (i=0 ; i<3 ; i++)
1108 if (bits & (SU_PUNCH1<<i))
1110 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1111 MSG_WriteChar(msg, (int)ent->fields.server->punchangle[i]);
1113 MSG_WriteAngle16i(msg, ent->fields.server->punchangle[i]);
1115 if (bits & (SU_PUNCHVEC1<<i))
1117 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1118 MSG_WriteCoord16i(msg, punchvector[i]);
1120 MSG_WriteCoord32f(msg, punchvector[i]);
1122 if (bits & (SU_VELOCITY1<<i))
1124 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1125 MSG_WriteChar(msg, (int)(ent->fields.server->velocity[i] * (1.0f / 16.0f)));
1127 MSG_WriteCoord32f(msg, ent->fields.server->velocity[i]);
1131 if (bits & SU_ITEMS)
1132 MSG_WriteLong (msg, stats[STAT_ITEMS]);
1134 if (sv.protocol == PROTOCOL_DARKPLACES5)
1136 if (bits & SU_WEAPONFRAME)
1137 MSG_WriteShort (msg, stats[STAT_WEAPONFRAME]);
1138 if (bits & SU_ARMOR)
1139 MSG_WriteShort (msg, stats[STAT_ARMOR]);
1140 if (bits & SU_WEAPON)
1141 MSG_WriteShort (msg, stats[STAT_WEAPON]);
1142 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1143 MSG_WriteShort (msg, stats[STAT_AMMO]);
1144 MSG_WriteShort (msg, stats[STAT_SHELLS]);
1145 MSG_WriteShort (msg, stats[STAT_NAILS]);
1146 MSG_WriteShort (msg, stats[STAT_ROCKETS]);
1147 MSG_WriteShort (msg, stats[STAT_CELLS]);
1148 MSG_WriteShort (msg, stats[STAT_ACTIVEWEAPON]);
1149 if (bits & SU_VIEWZOOM)
1150 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1152 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)
1154 if (bits & SU_WEAPONFRAME)
1155 MSG_WriteByte (msg, stats[STAT_WEAPONFRAME]);
1156 if (bits & SU_ARMOR)
1157 MSG_WriteByte (msg, stats[STAT_ARMOR]);
1158 if (bits & SU_WEAPON)
1159 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1160 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1161 MSG_WriteByte (msg, stats[STAT_AMMO]);
1162 MSG_WriteByte (msg, stats[STAT_SHELLS]);
1163 MSG_WriteByte (msg, stats[STAT_NAILS]);
1164 MSG_WriteByte (msg, stats[STAT_ROCKETS]);
1165 MSG_WriteByte (msg, stats[STAT_CELLS]);
1166 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_NEXUIZ)
1168 for (i = 0;i < 32;i++)
1169 if (stats[STAT_WEAPON] & (1<<i))
1171 MSG_WriteByte (msg, i);
1174 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1175 if (bits & SU_VIEWZOOM)
1177 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1178 MSG_WriteByte (msg, bound(0, stats[STAT_VIEWZOOM], 255));
1180 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1186 =======================
1187 SV_SendClientDatagram
1188 =======================
1190 static unsigned char sv_sendclientdatagram_buf[NET_MAXMESSAGE]; // FIXME?
1191 void SV_SendClientDatagram (client_t *client)
1193 int rate, maxrate, maxsize, maxsize2;
1195 int stats[MAX_CL_STATS];
1197 if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP && !sv_ratelimitlocalplayer.integer)
1199 // for good singleplayer, send huge packets
1200 maxsize = sizeof(sv_sendclientdatagram_buf);
1201 maxsize2 = sizeof(sv_sendclientdatagram_buf);
1203 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)
1205 // no rate limiting support on older protocols because dp protocols
1206 // 1-4 kick the client off if they overflow, and quake protocol shows
1207 // less than the full entity set if rate limited
1213 // PROTOCOL_DARKPLACES5 and later support packet size limiting of updates
1214 maxrate = bound(NET_MINRATE, sv_maxrate.integer, NET_MAXRATE);
1215 if (sv_maxrate.integer != maxrate)
1216 Cvar_SetValueQuick(&sv_maxrate, maxrate);
1218 // this rate limiting does not understand sys_ticrate 0
1219 // (but no one should be running that on a server!)
1220 rate = bound(NET_MINRATE, client->rate, maxrate);
1221 rate = (int)(client->rate * sys_ticrate.value);
1222 maxsize = bound(100, rate, 1400);
1226 msg.data = sv_sendclientdatagram_buf;
1227 msg.maxsize = maxsize;
1230 if (host_client->spawned)
1232 MSG_WriteByte (&msg, svc_time);
1233 MSG_WriteFloat (&msg, sv.time);
1235 // add the client specific data to the datagram
1236 SV_WriteClientdataToMessage (client, client->edict, &msg, stats);
1237 VM_SV_WriteAutoSentStats (client, client->edict, &msg, stats);
1238 SV_WriteEntitiesToClient (client, client->edict, &msg, stats);
1240 // expand packet size to allow effects to go over the rate limit
1241 // (dropping them is FAR too ugly)
1242 msg.maxsize = maxsize2;
1244 // copy the server datagram if there is space
1245 // FIXME: put in delayed queue of effects to send
1246 if (sv.datagram.cursize > 0 && msg.cursize + sv.datagram.cursize <= msg.maxsize)
1247 SZ_Write (&msg, sv.datagram.data, sv.datagram.cursize);
1249 else if (realtime > client->keepalivetime)
1251 // the player isn't totally in the game yet
1252 // send small keepalive messages if too much time has passed
1253 client->keepalivetime = realtime + 5;
1254 MSG_WriteChar (&msg, svc_nop);
1257 // send the datagram
1258 NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol);
1262 =======================
1263 SV_UpdateToReliableMessages
1264 =======================
1266 void SV_UpdateToReliableMessages (void)
1275 // check for changes to be sent over the reliable streams
1276 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1278 // update the host_client fields we care about according to the entity fields
1279 host_client->edict = PRVM_EDICT_NUM(i+1);
1282 name = PRVM_GetString(host_client->edict->fields.server->netname);
1285 // always point the string back at host_client->name to keep it safe
1286 strlcpy (host_client->name, name, sizeof (host_client->name));
1287 host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
1288 if (strcmp(host_client->old_name, host_client->name))
1290 if (host_client->spawned)
1291 SV_BroadcastPrintf("%s changed name to %s\n", host_client->old_name, host_client->name);
1292 strcpy(host_client->old_name, host_client->name);
1293 // send notification to all clients
1294 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
1295 MSG_WriteByte (&sv.reliable_datagram, i);
1296 MSG_WriteString (&sv.reliable_datagram, host_client->name);
1299 // DP_SV_CLIENTCOLORS
1300 // this is always found (since it's added by the progs loader)
1301 if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_clientcolors)))
1302 host_client->colors = (int)val->_float;
1303 if (host_client->old_colors != host_client->colors)
1305 host_client->old_colors = host_client->colors;
1306 // send notification to all clients
1307 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1308 MSG_WriteByte (&sv.reliable_datagram, i);
1309 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1312 // NEXUIZ_PLAYERMODEL
1313 if( eval_playermodel ) {
1314 model = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string);
1317 // always point the string back at host_client->name to keep it safe
1318 strlcpy (host_client->playermodel, model, sizeof (host_client->playermodel));
1319 PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
1322 // NEXUIZ_PLAYERSKIN
1323 if( eval_playerskin ) {
1324 skin = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string);
1327 // always point the string back at host_client->name to keep it safe
1328 strlcpy (host_client->playerskin, skin, sizeof (host_client->playerskin));
1329 PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
1333 host_client->frags = (int)host_client->edict->fields.server->frags;
1334 if (host_client->old_frags != host_client->frags)
1336 host_client->old_frags = host_client->frags;
1337 // send notification to all clients
1338 MSG_WriteByte (&sv.reliable_datagram, svc_updatefrags);
1339 MSG_WriteByte (&sv.reliable_datagram, i);
1340 MSG_WriteShort (&sv.reliable_datagram, host_client->frags);
1344 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1345 if (client->netconnection)
1346 SZ_Write (&client->netconnection->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
1348 SZ_Clear (&sv.reliable_datagram);
1353 =======================
1354 SV_SendClientMessages
1355 =======================
1357 void SV_SendClientMessages (void)
1359 int i, prepared = false;
1361 if (sv.protocol == PROTOCOL_QUAKEWORLD)
1362 Sys_Error("SV_SendClientMessages: no quakeworld support\n");
1364 // update frags, names, etc
1365 SV_UpdateToReliableMessages();
1367 // build individual updates
1368 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1370 if (!host_client->active)
1372 if (!host_client->netconnection)
1375 if (host_client->netconnection->message.overflowed)
1377 SV_DropClient (true); // if the message couldn't send, kick off
1384 // only prepare entities once per frame
1385 SV_PrepareEntitiesForSending();
1387 SV_SendClientDatagram (host_client);
1390 // clear muzzle flashes
1396 ==============================================================================
1400 ==============================================================================
1409 int SV_ModelIndex(const char *s, int precachemode)
1411 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_MODELS);
1412 char filename[MAX_QPATH];
1416 //if (precachemode == 2)
1418 strlcpy(filename, s, sizeof(filename));
1419 for (i = 2;i < limit;i++)
1421 if (!sv.model_precache[i][0])
1425 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))
1427 Con_Printf("SV_ModelIndex(\"%s\"): precache_model can only be done in spawn functions\n", filename);
1430 if (precachemode == 1)
1431 Con_Printf("SV_ModelIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1432 strlcpy(sv.model_precache[i], filename, sizeof(sv.model_precache[i]));
1433 sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, false);
1434 if (sv.state != ss_loading)
1436 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1437 MSG_WriteShort(&sv.reliable_datagram, i);
1438 MSG_WriteString(&sv.reliable_datagram, filename);
1442 Con_Printf("SV_ModelIndex(\"%s\"): not precached\n", filename);
1445 if (!strcmp(sv.model_precache[i], filename))
1448 Con_Printf("SV_ModelIndex(\"%s\"): i (%i) == MAX_MODELS (%i)\n", filename, i, MAX_MODELS);
1458 int SV_SoundIndex(const char *s, int precachemode)
1460 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_SOUNDS);
1461 char filename[MAX_QPATH];
1465 //if (precachemode == 2)
1467 strlcpy(filename, s, sizeof(filename));
1468 for (i = 1;i < limit;i++)
1470 if (!sv.sound_precache[i][0])
1474 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))
1476 Con_Printf("SV_SoundIndex(\"%s\"): precache_sound can only be done in spawn functions\n", filename);
1479 if (precachemode == 1)
1480 Con_Printf("SV_SoundIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1481 strlcpy(sv.sound_precache[i], filename, sizeof(sv.sound_precache[i]));
1482 if (sv.state != ss_loading)
1484 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1485 MSG_WriteShort(&sv.reliable_datagram, i + 32768);
1486 MSG_WriteString(&sv.reliable_datagram, filename);
1490 Con_Printf("SV_SoundIndex(\"%s\"): not precached\n", filename);
1493 if (!strcmp(sv.sound_precache[i], filename))
1496 Con_Printf("SV_SoundIndex(\"%s\"): i (%i) == MAX_SOUNDS (%i)\n", filename, i, MAX_SOUNDS);
1506 void SV_CreateBaseline (void)
1508 int i, entnum, large;
1509 prvm_edict_t *svent;
1511 // LordHavoc: clear *all* states (note just active ones)
1512 for (entnum = 0;entnum < prog->max_edicts;entnum++)
1514 // get the current server version
1515 svent = PRVM_EDICT_NUM(entnum);
1517 // LordHavoc: always clear state values, whether the entity is in use or not
1518 svent->priv.server->baseline = defaultstate;
1520 if (svent->priv.server->free)
1522 if (entnum > svs.maxclients && !svent->fields.server->modelindex)
1525 // create entity baseline
1526 VectorCopy (svent->fields.server->origin, svent->priv.server->baseline.origin);
1527 VectorCopy (svent->fields.server->angles, svent->priv.server->baseline.angles);
1528 svent->priv.server->baseline.frame = (int)svent->fields.server->frame;
1529 svent->priv.server->baseline.skin = (int)svent->fields.server->skin;
1530 if (entnum > 0 && entnum <= svs.maxclients)
1532 svent->priv.server->baseline.colormap = entnum;
1533 svent->priv.server->baseline.modelindex = SV_ModelIndex("progs/player.mdl", 1);
1537 svent->priv.server->baseline.colormap = 0;
1538 svent->priv.server->baseline.modelindex = (int)svent->fields.server->modelindex;
1542 if (svent->priv.server->baseline.modelindex & 0xFF00 || svent->priv.server->baseline.frame & 0xFF00)
1545 // add to the message
1547 MSG_WriteByte (&sv.signon, svc_spawnbaseline2);
1549 MSG_WriteByte (&sv.signon, svc_spawnbaseline);
1550 MSG_WriteShort (&sv.signon, entnum);
1554 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.modelindex);
1555 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.frame);
1559 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.modelindex);
1560 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.frame);
1562 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.colormap);
1563 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.skin);
1564 for (i=0 ; i<3 ; i++)
1566 MSG_WriteCoord(&sv.signon, svent->priv.server->baseline.origin[i], sv.protocol);
1567 MSG_WriteAngle(&sv.signon, svent->priv.server->baseline.angles[i], sv.protocol);
1577 Grabs the current state of each client for saving across the
1578 transition to another level
1581 void SV_SaveSpawnparms (void)
1585 svs.serverflags = (int)prog->globals.server->serverflags;
1587 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1589 if (!host_client->active)
1592 // call the progs to get default spawn parms for the new client
1593 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1594 PRVM_ExecuteProgram (prog->globals.server->SetChangeParms, "QC function SetChangeParms is missing");
1595 for (j=0 ; j<NUM_SPAWN_PARMS ; j++)
1596 host_client->spawn_parms[j] = (&prog->globals.server->parm1)[j];
1600 void SV_IncreaseEdicts(void)
1604 int oldmax_edicts = prog->max_edicts;
1605 void *oldedictsengineprivate = prog->edictprivate;
1606 void *oldedictsfields = prog->edictsfields;
1607 void *oldmoved_edicts = sv.moved_edicts;
1609 if (prog->max_edicts >= MAX_EDICTS)
1612 // links don't survive the transition, so unlink everything
1613 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1615 if (!ent->priv.server->free)
1616 SV_UnlinkEdict(prog->edicts + i);
1617 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
1621 prog->max_edicts = min(prog->max_edicts + 256, MAX_EDICTS);
1622 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
1623 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);
1624 sv.moved_edicts = PR_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1626 memcpy(prog->edictprivate, oldedictsengineprivate, oldmax_edicts * sizeof(edict_engineprivate_t));
1627 memcpy(prog->edictsfields, oldedictsfields, oldmax_edicts * prog->edict_size);
1629 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1631 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
1632 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
1633 // link every entity except world
1634 if (!ent->priv.server->free)
1635 SV_LinkEdict(ent, false);
1638 PR_Free(oldedictsengineprivate);
1639 PR_Free(oldedictsfields);
1640 PR_Free(oldmoved_edicts);
1647 This is called at the start of each level
1650 extern float scr_centertime_off;
1652 void SV_SpawnServer (const char *server)
1657 model_t *worldmodel;
1658 char modelname[sizeof(sv.modelname)];
1660 Con_DPrintf("SpawnServer: %s\n", server);
1662 if (cls.state != ca_dedicated)
1663 SCR_BeginLoadingPlaque();
1665 dpsnprintf (modelname, sizeof(modelname), "maps/%s.bsp", server);
1666 worldmodel = Mod_ForName(modelname, false, true, true);
1667 if (!worldmodel || !worldmodel->TraceBox)
1669 Con_Printf("Couldn't load map %s\n", modelname);
1673 // let's not have any servers with no name
1674 if (hostname.string[0] == 0)
1675 Cvar_Set ("hostname", "UNNAMED");
1676 scr_centertime_off = 0;
1678 svs.changelevel_issued = false; // now safe to issue another
1681 // tell all connected clients that we are going to a new level
1686 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
1688 if (client->netconnection)
1690 MSG_WriteByte(&client->netconnection->message, svc_stufftext);
1691 MSG_WriteString(&client->netconnection->message, "reconnect\n");
1698 NetConn_OpenServerPorts(true);
1702 // make cvars consistant
1705 Cvar_SetValue ("deathmatch", 0);
1706 // LordHavoc: it can be useful to have skills outside the range 0-3...
1707 //current_skill = bound(0, (int)(skill.value + 0.5), 3);
1708 //Cvar_SetValue ("skill", (float)current_skill);
1709 current_skill = (int)(skill.value + 0.5);
1712 // set up the new server
1714 memset (&sv, 0, sizeof(sv));
1715 // if running a local client, make sure it doesn't try to access the last
1716 // level's data which is no longer valiud
1723 strlcpy (sv.name, server, sizeof (sv.name));
1725 sv.protocol = Protocol_EnumForName(sv_protocolname.string);
1726 if (sv.protocol == PROTOCOL_UNKNOWN)
1729 Protocol_Names(buffer, sizeof(buffer));
1730 Con_Printf("Unknown sv_protocolname \"%s\", valid values are:\n%s\n", sv_protocolname.string, buffer);
1731 sv.protocol = PROTOCOL_QUAKE;
1736 // load progs to get entity field count
1737 //PR_LoadProgs ( sv_progs.string );
1739 // allocate server memory
1740 /*// start out with just enough room for clients and a reasonable estimate of entities
1741 prog->max_edicts = max(svs.maxclients + 1, 512);
1742 prog->max_edicts = min(prog->max_edicts, MAX_EDICTS);
1744 // prvm_edict_t structures (hidden from progs)
1745 prog->edicts = PR_Alloc(MAX_EDICTS * sizeof(prvm_edict_t));
1746 // engine private structures (hidden from progs)
1747 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
1748 // progs fields, often accessed by server
1749 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);*/
1750 // used by PushMove to move back pushed entities
1751 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1752 /*for (i = 0;i < prog->max_edicts;i++)
1754 ent = prog->edicts + i;
1755 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
1756 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
1759 // reset client csqc entity versions right away.
1760 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1761 EntityFrameCSQC_InitClientVersions(i, true);
1763 sv.datagram.maxsize = sizeof(sv.datagram_buf);
1764 sv.datagram.cursize = 0;
1765 sv.datagram.data = sv.datagram_buf;
1767 sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf);
1768 sv.reliable_datagram.cursize = 0;
1769 sv.reliable_datagram.data = sv.reliable_datagram_buf;
1771 sv.signon.maxsize = sizeof(sv.signon_buf);
1772 sv.signon.cursize = 0;
1773 sv.signon.data = sv.signon_buf;
1775 // leave slots at start for clients only
1776 //prog->num_edicts = svs.maxclients+1;
1778 sv.state = ss_loading;
1779 prog->allowworldwrites = true;
1782 *prog->time = sv.time = 1.0;
1785 worldmodel->used = true;
1787 strlcpy (sv.name, server, sizeof (sv.name));
1788 strcpy(sv.modelname, modelname);
1789 sv.worldmodel = worldmodel;
1790 sv.models[1] = sv.worldmodel;
1793 // clear world interaction links
1797 strlcpy(sv.sound_precache[0], "", sizeof(sv.sound_precache[0]));
1799 strlcpy(sv.model_precache[0], "", sizeof(sv.model_precache[0]));
1800 strlcpy(sv.model_precache[1], sv.modelname, sizeof(sv.model_precache[1]));
1801 for (i = 1;i < sv.worldmodel->brush.numsubmodels;i++)
1803 dpsnprintf(sv.model_precache[i+1], sizeof(sv.model_precache[i+1]), "*%i", i);
1804 sv.models[i+1] = Mod_ForName (sv.model_precache[i+1], false, false, false);
1808 // load the rest of the entities
1810 // AK possible hack since num_edicts is still 0
1811 ent = PRVM_EDICT_NUM(0);
1812 memset (ent->fields.server, 0, prog->progs->entityfields * 4);
1813 ent->priv.server->free = false;
1814 ent->fields.server->model = PRVM_SetEngineString(sv.modelname);
1815 ent->fields.server->modelindex = 1; // world model
1816 ent->fields.server->solid = SOLID_BSP;
1817 ent->fields.server->movetype = MOVETYPE_PUSH;
1820 prog->globals.server->coop = coop.integer;
1822 prog->globals.server->deathmatch = deathmatch.integer;
1824 prog->globals.server->mapname = PRVM_SetEngineString(sv.name);
1826 // serverflags are for cross level information (sigils)
1827 prog->globals.server->serverflags = svs.serverflags;
1829 // we need to reset the spawned flag on all connected clients here so that
1830 // their thinks don't run during startup (before PutClientInServer)
1831 // we also need to set up the client entities now
1832 // and we need to set the ->edict pointers to point into the progs edicts
1833 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1835 host_client->spawned = false;
1836 host_client->edict = PRVM_EDICT_NUM(i + 1);
1837 PRVM_ED_ClearEdict(host_client->edict);
1840 // load replacement entity file if found
1841 if (sv_entpatch.integer && (entities = (char *)FS_LoadFile(va("maps/%s.ent", sv.name), tempmempool, true, NULL)))
1843 Con_Printf("Loaded maps/%s.ent\n", sv.name);
1844 PRVM_ED_LoadFromFile (entities);
1848 PRVM_ED_LoadFromFile (sv.worldmodel->brush.entities);
1851 // LordHavoc: clear world angles (to fix e3m3.bsp)
1852 VectorClear(prog->edicts->fields.server->angles);
1854 // all setup is completed, any further precache statements are errors
1855 sv.state = ss_active;
1856 prog->allowworldwrites = false;
1858 // run two frames to allow everything to settle
1859 for (i = 0;i < 2;i++)
1867 // create a baseline for more efficient communications
1868 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1869 SV_CreateBaseline ();
1871 // send serverinfo to all connected clients, and set up botclients coming back from a level change
1872 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1874 if (!host_client->active)
1876 if (host_client->netconnection)
1877 SV_SendServerinfo(host_client);
1881 // if client is a botclient coming from a level change, we need to
1882 // set up client info that normally requires networking
1884 // copy spawn parms out of the client_t
1885 for (j=0 ; j< NUM_SPAWN_PARMS ; j++)
1886 (&prog->globals.server->parm1)[j] = host_client->spawn_parms[j];
1888 // call the spawn function
1889 host_client->clientconnectcalled = true;
1890 prog->globals.server->time = sv.time;
1891 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1892 PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
1893 PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
1894 host_client->spawned = true;
1898 Con_DPrint("Server spawned.\n");
1899 NetConn_Heartbeat (2);
1904 /////////////////////////////////////////////////////
1907 void SV_VM_CB_BeginIncreaseEdicts(void)
1912 PRVM_Free( sv.moved_edicts );
1913 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1915 // links don't survive the transition, so unlink everything
1916 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1918 if (!ent->priv.server->free)
1919 SV_UnlinkEdict(prog->edicts + i);
1920 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
1925 void SV_VM_CB_EndIncreaseEdicts(void)
1930 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1932 // link every entity except world
1933 if (!ent->priv.server->free)
1934 SV_LinkEdict(ent, false);
1938 void SV_VM_CB_InitEdict(prvm_edict_t *e)
1940 // LordHavoc: for consistency set these here
1941 int num = PRVM_NUM_FOR_EDICT(e) - 1;
1943 e->priv.server->move = false; // don't move on first frame
1945 if (num >= 0 && num < svs.maxclients)
1948 // set colormap and team on newly created player entity
1949 e->fields.server->colormap = num + 1;
1950 e->fields.server->team = (svs.clients[num].colors & 15) + 1;
1951 // set netname/clientcolors back to client values so that
1952 // DP_SV_CLIENTNAME and DP_SV_CLIENTCOLORS will not immediately
1954 e->fields.server->netname = PRVM_SetEngineString(svs.clients[num].name);
1955 if ((val = PRVM_GETEDICTFIELDVALUE(e, eval_clientcolors)))
1956 val->_float = svs.clients[num].colors;
1957 // NEXUIZ_PLAYERMODEL and NEXUIZ_PLAYERSKIN
1958 if( eval_playermodel )
1959 PRVM_GETEDICTFIELDVALUE(e, eval_playermodel)->string = PRVM_SetEngineString(svs.clients[num].playermodel);
1960 if( eval_playerskin )
1961 PRVM_GETEDICTFIELDVALUE(e, eval_playerskin)->string = PRVM_SetEngineString(svs.clients[num].playerskin);
1965 void SV_VM_CB_FreeEdict(prvm_edict_t *ed)
1967 SV_UnlinkEdict (ed); // unlink from world bsp
1969 ed->fields.server->model = 0;
1970 ed->fields.server->takedamage = 0;
1971 ed->fields.server->modelindex = 0;
1972 ed->fields.server->colormap = 0;
1973 ed->fields.server->skin = 0;
1974 ed->fields.server->frame = 0;
1975 VectorClear(ed->fields.server->origin);
1976 VectorClear(ed->fields.server->angles);
1977 ed->fields.server->nextthink = -1;
1978 ed->fields.server->solid = 0;
1981 void SV_VM_CB_CountEdicts(void)
1985 int active, models, solid, step;
1987 active = models = solid = step = 0;
1988 for (i=0 ; i<prog->num_edicts ; i++)
1990 ent = PRVM_EDICT_NUM(i);
1991 if (ent->priv.server->free)
1994 if (ent->fields.server->solid)
1996 if (ent->fields.server->model)
1998 if (ent->fields.server->movetype == MOVETYPE_STEP)
2002 Con_Printf("num_edicts:%3i\n", prog->num_edicts);
2003 Con_Printf("active :%3i\n", active);
2004 Con_Printf("view :%3i\n", models);
2005 Con_Printf("touch :%3i\n", solid);
2006 Con_Printf("step :%3i\n", step);
2009 qboolean SV_VM_CB_LoadEdict(prvm_edict_t *ent)
2011 // remove things from different skill levels or deathmatch
2012 if (gamemode != GAME_TRANSFUSION) //Transfusion does this in QC
2014 if (deathmatch.integer)
2016 if (((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
2021 else if ((current_skill <= 0 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_EASY ))
2022 || (current_skill == 1 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_MEDIUM))
2023 || (current_skill >= 2 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_HARD )))
2031 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)"};
2032 cvar_t nomonsters = {0, "nomonsters", "0", "unused cvar in quake, can be used by mods"};
2033 cvar_t gamecfg = {0, "gamecfg", "0", "unused cvar in quake, can be used by mods"};
2034 cvar_t scratch1 = {0, "scratch1", "0", "unused cvar in quake, can be used by mods"};
2035 cvar_t scratch2 = {0,"scratch2", "0", "unused cvar in quake, can be used by mods"};
2036 cvar_t scratch3 = {0, "scratch3", "0", "unused cvar in quake, can be used by mods"};
2037 cvar_t scratch4 = {0, "scratch4", "0", "unused cvar in quake, can be used by mods"};
2038 cvar_t savedgamecfg = {CVAR_SAVE, "savedgamecfg", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2039 cvar_t saved1 = {CVAR_SAVE, "saved1", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2040 cvar_t saved2 = {CVAR_SAVE, "saved2", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2041 cvar_t saved3 = {CVAR_SAVE, "saved3", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2042 cvar_t saved4 = {CVAR_SAVE, "saved4", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2043 cvar_t nehx00 = {0, "nehx00", "0", "nehahra data storage cvar (used in singleplayer)"};
2044 cvar_t nehx01 = {0, "nehx01", "0", "nehahra data storage cvar (used in singleplayer)"};
2045 cvar_t nehx02 = {0, "nehx02", "0", "nehahra data storage cvar (used in singleplayer)"};
2046 cvar_t nehx03 = {0, "nehx03", "0", "nehahra data storage cvar (used in singleplayer)"};
2047 cvar_t nehx04 = {0, "nehx04", "0", "nehahra data storage cvar (used in singleplayer)"};
2048 cvar_t nehx05 = {0, "nehx05", "0", "nehahra data storage cvar (used in singleplayer)"};
2049 cvar_t nehx06 = {0, "nehx06", "0", "nehahra data storage cvar (used in singleplayer)"};
2050 cvar_t nehx07 = {0, "nehx07", "0", "nehahra data storage cvar (used in singleplayer)"};
2051 cvar_t nehx08 = {0, "nehx08", "0", "nehahra data storage cvar (used in singleplayer)"};
2052 cvar_t nehx09 = {0, "nehx09", "0", "nehahra data storage cvar (used in singleplayer)"};
2053 cvar_t nehx10 = {0, "nehx10", "0", "nehahra data storage cvar (used in singleplayer)"};
2054 cvar_t nehx11 = {0, "nehx11", "0", "nehahra data storage cvar (used in singleplayer)"};
2055 cvar_t nehx12 = {0, "nehx12", "0", "nehahra data storage cvar (used in singleplayer)"};
2056 cvar_t nehx13 = {0, "nehx13", "0", "nehahra data storage cvar (used in singleplayer)"};
2057 cvar_t nehx14 = {0, "nehx14", "0", "nehahra data storage cvar (used in singleplayer)"};
2058 cvar_t nehx15 = {0, "nehx15", "0", "nehahra data storage cvar (used in singleplayer)"};
2059 cvar_t nehx16 = {0, "nehx16", "0", "nehahra data storage cvar (used in singleplayer)"};
2060 cvar_t nehx17 = {0, "nehx17", "0", "nehahra data storage cvar (used in singleplayer)"};
2061 cvar_t nehx18 = {0, "nehx18", "0", "nehahra data storage cvar (used in singleplayer)"};
2062 cvar_t nehx19 = {0, "nehx19", "0", "nehahra data storage cvar (used in singleplayer)"};
2063 cvar_t cutscene = {0, "cutscene", "1", "enables cutscenes in nehahra, can be used by other mods"};
2065 void SV_VM_Init(void)
2067 Cvar_RegisterVariable (&pr_checkextension);
2068 Cvar_RegisterVariable (&nomonsters);
2069 Cvar_RegisterVariable (&gamecfg);
2070 Cvar_RegisterVariable (&scratch1);
2071 Cvar_RegisterVariable (&scratch2);
2072 Cvar_RegisterVariable (&scratch3);
2073 Cvar_RegisterVariable (&scratch4);
2074 Cvar_RegisterVariable (&savedgamecfg);
2075 Cvar_RegisterVariable (&saved1);
2076 Cvar_RegisterVariable (&saved2);
2077 Cvar_RegisterVariable (&saved3);
2078 Cvar_RegisterVariable (&saved4);
2079 // LordHavoc: Nehahra uses these to pass data around cutscene demos
2080 if (gamemode == GAME_NEHAHRA)
2082 Cvar_RegisterVariable (&nehx00);
2083 Cvar_RegisterVariable (&nehx01);
2084 Cvar_RegisterVariable (&nehx02);
2085 Cvar_RegisterVariable (&nehx03);
2086 Cvar_RegisterVariable (&nehx04);
2087 Cvar_RegisterVariable (&nehx05);
2088 Cvar_RegisterVariable (&nehx06);
2089 Cvar_RegisterVariable (&nehx07);
2090 Cvar_RegisterVariable (&nehx08);
2091 Cvar_RegisterVariable (&nehx09);
2092 Cvar_RegisterVariable (&nehx10);
2093 Cvar_RegisterVariable (&nehx11);
2094 Cvar_RegisterVariable (&nehx12);
2095 Cvar_RegisterVariable (&nehx13);
2096 Cvar_RegisterVariable (&nehx14);
2097 Cvar_RegisterVariable (&nehx15);
2098 Cvar_RegisterVariable (&nehx16);
2099 Cvar_RegisterVariable (&nehx17);
2100 Cvar_RegisterVariable (&nehx18);
2101 Cvar_RegisterVariable (&nehx19);
2103 Cvar_RegisterVariable (&cutscene); // for Nehahra but useful to other mods as well
2106 // LordHavoc: in an effort to eliminate time wasted on GetEdictFieldValue... these are defined as externs in progs.h
2123 int eval_buttonchat;
2125 int eval_glow_trail;
2126 int eval_glow_color;
2130 int eval_renderamt; // HalfLife support
2131 int eval_rendermode; // HalfLife support
2132 int eval_fullbright;
2133 int eval_ammo_shells1;
2134 int eval_ammo_nails1;
2135 int eval_ammo_lava_nails;
2136 int eval_ammo_rockets1;
2137 int eval_ammo_multi_rockets;
2138 int eval_ammo_cells1;
2139 int eval_ammo_plasma;
2140 int eval_idealpitch;
2141 int eval_pitch_speed;
2142 int eval_viewmodelforclient;
2143 int eval_nodrawtoclient;
2144 int eval_exteriormodeltoclient;
2145 int eval_drawonlytoclient;
2149 int eval_punchvector;
2151 int eval_clientcolors;
2152 int eval_tag_entity;
2158 int eval_cursor_active;
2159 int eval_cursor_screen;
2160 int eval_cursor_trace_start;
2161 int eval_cursor_trace_endpos;
2162 int eval_cursor_trace_ent;
2164 int eval_playermodel;
2165 int eval_playerskin;
2166 int eval_SendEntity;
2168 int eval_customizeentityforclient;
2169 int eval_dphitcontentsmask;
2171 int gval_trace_dpstartcontents;
2172 int gval_trace_dphitcontents;
2173 int gval_trace_dphitq3surfaceflags;
2174 int gval_trace_dphittexturename;
2176 mfunction_t *SV_PlayerPhysicsQC;
2177 mfunction_t *EndFrameQC;
2178 //KrimZon - SERVER COMMANDS IN QUAKEC
2179 mfunction_t *SV_ParseClientCommandQC;
2181 ddef_t *PRVM_ED_FindGlobal(const char *name);
2183 void SV_VM_FindEdictFieldOffsets(void)
2185 eval_gravity = PRVM_ED_FindFieldOffset("gravity");
2186 eval_button3 = PRVM_ED_FindFieldOffset("button3");
2187 eval_button4 = PRVM_ED_FindFieldOffset("button4");
2188 eval_button5 = PRVM_ED_FindFieldOffset("button5");
2189 eval_button6 = PRVM_ED_FindFieldOffset("button6");
2190 eval_button7 = PRVM_ED_FindFieldOffset("button7");
2191 eval_button8 = PRVM_ED_FindFieldOffset("button8");
2192 eval_button9 = PRVM_ED_FindFieldOffset("button9");
2193 eval_button10 = PRVM_ED_FindFieldOffset("button10");
2194 eval_button11 = PRVM_ED_FindFieldOffset("button11");
2195 eval_button12 = PRVM_ED_FindFieldOffset("button12");
2196 eval_button13 = PRVM_ED_FindFieldOffset("button13");
2197 eval_button14 = PRVM_ED_FindFieldOffset("button14");
2198 eval_button15 = PRVM_ED_FindFieldOffset("button15");
2199 eval_button16 = PRVM_ED_FindFieldOffset("button16");
2200 eval_buttonuse = PRVM_ED_FindFieldOffset("buttonuse");
2201 eval_buttonchat = PRVM_ED_FindFieldOffset("buttonchat");
2202 eval_glow_size = PRVM_ED_FindFieldOffset("glow_size");
2203 eval_glow_trail = PRVM_ED_FindFieldOffset("glow_trail");
2204 eval_glow_color = PRVM_ED_FindFieldOffset("glow_color");
2205 eval_items2 = PRVM_ED_FindFieldOffset("items2");
2206 eval_scale = PRVM_ED_FindFieldOffset("scale");
2207 eval_alpha = PRVM_ED_FindFieldOffset("alpha");
2208 eval_renderamt = PRVM_ED_FindFieldOffset("renderamt"); // HalfLife support
2209 eval_rendermode = PRVM_ED_FindFieldOffset("rendermode"); // HalfLife support
2210 eval_fullbright = PRVM_ED_FindFieldOffset("fullbright");
2211 eval_ammo_shells1 = PRVM_ED_FindFieldOffset("ammo_shells1");
2212 eval_ammo_nails1 = PRVM_ED_FindFieldOffset("ammo_nails1");
2213 eval_ammo_lava_nails = PRVM_ED_FindFieldOffset("ammo_lava_nails");
2214 eval_ammo_rockets1 = PRVM_ED_FindFieldOffset("ammo_rockets1");
2215 eval_ammo_multi_rockets = PRVM_ED_FindFieldOffset("ammo_multi_rockets");
2216 eval_ammo_cells1 = PRVM_ED_FindFieldOffset("ammo_cells1");
2217 eval_ammo_plasma = PRVM_ED_FindFieldOffset("ammo_plasma");
2218 eval_idealpitch = PRVM_ED_FindFieldOffset("idealpitch");
2219 eval_pitch_speed = PRVM_ED_FindFieldOffset("pitch_speed");
2220 eval_viewmodelforclient = PRVM_ED_FindFieldOffset("viewmodelforclient");
2221 eval_nodrawtoclient = PRVM_ED_FindFieldOffset("nodrawtoclient");
2222 eval_exteriormodeltoclient = PRVM_ED_FindFieldOffset("exteriormodeltoclient");
2223 eval_drawonlytoclient = PRVM_ED_FindFieldOffset("drawonlytoclient");
2224 eval_ping = PRVM_ED_FindFieldOffset("ping");
2225 eval_movement = PRVM_ED_FindFieldOffset("movement");
2226 eval_pmodel = PRVM_ED_FindFieldOffset("pmodel");
2227 eval_punchvector = PRVM_ED_FindFieldOffset("punchvector");
2228 eval_viewzoom = PRVM_ED_FindFieldOffset("viewzoom");
2229 eval_clientcolors = PRVM_ED_FindFieldOffset("clientcolors");
2230 eval_tag_entity = PRVM_ED_FindFieldOffset("tag_entity");
2231 eval_tag_index = PRVM_ED_FindFieldOffset("tag_index");
2232 eval_light_lev = PRVM_ED_FindFieldOffset("light_lev");
2233 eval_color = PRVM_ED_FindFieldOffset("color");
2234 eval_style = PRVM_ED_FindFieldOffset("style");
2235 eval_pflags = PRVM_ED_FindFieldOffset("pflags");
2236 eval_cursor_active = PRVM_ED_FindFieldOffset("cursor_active");
2237 eval_cursor_screen = PRVM_ED_FindFieldOffset("cursor_screen");
2238 eval_cursor_trace_start = PRVM_ED_FindFieldOffset("cursor_trace_start");
2239 eval_cursor_trace_endpos = PRVM_ED_FindFieldOffset("cursor_trace_endpos");
2240 eval_cursor_trace_ent = PRVM_ED_FindFieldOffset("cursor_trace_ent");
2241 eval_colormod = PRVM_ED_FindFieldOffset("colormod");
2242 eval_playermodel = PRVM_ED_FindFieldOffset("playermodel");
2243 eval_playerskin = PRVM_ED_FindFieldOffset("playerskin");
2244 eval_SendEntity = PRVM_ED_FindFieldOffset("SendEntity");
2245 eval_Version = PRVM_ED_FindFieldOffset("Version");
2246 eval_customizeentityforclient = PRVM_ED_FindFieldOffset("customizeentityforclient");
2247 eval_dphitcontentsmask = PRVM_ED_FindFieldOffset("dphitcontentsmask");
2249 // LordHavoc: allowing QuakeC to override the player movement code
2250 SV_PlayerPhysicsQC = PRVM_ED_FindFunction ("SV_PlayerPhysics");
2251 // LordHavoc: support for endframe
2252 EndFrameQC = PRVM_ED_FindFunction ("EndFrame");
2253 //KrimZon - SERVER COMMANDS IN QUAKEC
2254 SV_ParseClientCommandQC = PRVM_ED_FindFunction ("SV_ParseClientCommand");
2256 //[515]: init stufftext string (it is sent before svc_serverinfo)
2257 if(PRVM_ED_FindGlobal("SV_InitCmd") && PRVM_ED_FindGlobal("SV_InitCmd")->type & ev_string)
2258 SV_InitCmd = PRVM_G_STRING(PRVM_ED_FindGlobal("SV_InitCmd")->ofs);
2262 gval_trace_dpstartcontents = PRVM_ED_FindGlobalOffset("trace_dpstartcontents");
2263 gval_trace_dphitcontents = PRVM_ED_FindGlobalOffset("trace_dphitcontents");
2264 gval_trace_dphitq3surfaceflags = PRVM_ED_FindGlobalOffset("trace_dphitq3surfaceflags");
2265 gval_trace_dphittexturename = PRVM_ED_FindGlobalOffset("trace_dphittexturename");
2268 #define REQFIELDS (sizeof(reqfields) / sizeof(prvm_required_field_t))
2270 prvm_required_field_t reqfields[] =
2272 {ev_entity, "cursor_trace_ent"},
2273 {ev_entity, "drawonlytoclient"},
2274 {ev_entity, "exteriormodeltoclient"},
2275 {ev_entity, "nodrawtoclient"},
2276 {ev_entity, "tag_entity"},
2277 {ev_entity, "viewmodelforclient"},
2278 {ev_float, "alpha"},
2279 {ev_float, "ammo_cells1"},
2280 {ev_float, "ammo_lava_nails"},
2281 {ev_float, "ammo_multi_rockets"},
2282 {ev_float, "ammo_nails1"},
2283 {ev_float, "ammo_plasma"},
2284 {ev_float, "ammo_rockets1"},
2285 {ev_float, "ammo_shells1"},
2286 {ev_float, "button3"},
2287 {ev_float, "button4"},
2288 {ev_float, "button5"},
2289 {ev_float, "button6"},
2290 {ev_float, "button7"},
2291 {ev_float, "button8"},
2292 {ev_float, "button9"},
2293 {ev_float, "button10"},
2294 {ev_float, "button11"},
2295 {ev_float, "button12"},
2296 {ev_float, "button13"},
2297 {ev_float, "button14"},
2298 {ev_float, "button15"},
2299 {ev_float, "button16"},
2300 {ev_float, "buttonchat"},
2301 {ev_float, "buttonuse"},
2302 {ev_float, "clientcolors"},
2303 {ev_float, "cursor_active"},
2304 {ev_float, "fullbright"},
2305 {ev_float, "glow_color"},
2306 {ev_float, "glow_size"},
2307 {ev_float, "glow_trail"},
2308 {ev_float, "gravity"},
2309 {ev_float, "idealpitch"},
2310 {ev_float, "items2"},
2311 {ev_float, "light_lev"},
2312 {ev_float, "pflags"},
2314 {ev_float, "pitch_speed"},
2315 {ev_float, "pmodel"},
2316 {ev_float, "renderamt"}, // HalfLife support
2317 {ev_float, "rendermode"}, // HalfLife support
2318 {ev_float, "scale"},
2319 {ev_float, "style"},
2320 {ev_float, "tag_index"},
2321 {ev_float, "Version"},
2322 {ev_float, "viewzoom"},
2323 {ev_vector, "color"},
2324 {ev_vector, "colormod"},
2325 {ev_vector, "cursor_screen"},
2326 {ev_vector, "cursor_trace_endpos"},
2327 {ev_vector, "cursor_trace_start"},
2328 {ev_vector, "movement"},
2329 {ev_vector, "punchvector"},
2330 {ev_string, "playermodel"},
2331 {ev_string, "playerskin"},
2332 {ev_function, "SendEntity"},
2333 {ev_function, "customizeentityforclient"},
2336 void SV_VM_Setup(void)
2339 PRVM_InitProg( PRVM_SERVERPROG );
2341 // allocate the mempools
2342 prog->progs_mempool = Mem_AllocPool("Server Progs", 0, NULL);
2343 prog->builtins = vm_sv_builtins;
2344 prog->numbuiltins = vm_sv_numbuiltins;
2345 prog->headercrc = PROGHEADER_CRC;
2346 prog->max_edicts = 512;
2347 prog->limit_edicts = MAX_EDICTS;
2348 prog->reserved_edicts = svs.maxclients;
2349 prog->edictprivate_size = sizeof(edict_engineprivate_t);
2350 prog->name = "server";
2351 prog->extensionstring = vm_sv_extensions;
2352 prog->loadintoworld = true;
2354 prog->begin_increase_edicts = SV_VM_CB_BeginIncreaseEdicts;
2355 prog->end_increase_edicts = SV_VM_CB_EndIncreaseEdicts;
2356 prog->init_edict = SV_VM_CB_InitEdict;
2357 prog->free_edict = SV_VM_CB_FreeEdict;
2358 prog->count_edicts = SV_VM_CB_CountEdicts;
2359 prog->load_edict = SV_VM_CB_LoadEdict;
2360 prog->init_cmd = VM_SV_Cmd_Init;
2361 prog->reset_cmd = VM_SV_Cmd_Reset;
2362 prog->error_cmd = Host_Error;
2364 // TODO: add a requiredfuncs list (ask LH if this is necessary at all)
2365 PRVM_LoadProgs( sv_progs.string, 0, NULL, REQFIELDS, reqfields );
2366 SV_VM_FindEdictFieldOffsets();
2368 VM_AutoSentStats_Clear();//[515]: csqc
2369 EntityFrameCSQC_ClearVersions();//[515]: csqc
2374 void SV_VM_Begin(void)
2377 PRVM_SetProg( PRVM_SERVERPROG );
2379 *prog->time = (float) sv.time;
2382 void SV_VM_End(void)