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
28 void VM_AutoSentStats_Clear (void);
29 void EntityFrameCSQC_ClearVersions (void);
30 void EntityFrameCSQC_InitClientVersions (int client, qboolean clear);
31 void VM_SV_WriteAutoSentStats (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats);
32 void EntityFrameCSQC_WriteFrame (sizebuf_t *msg, int numstates, const entity_state_t *states);
35 // select which protocol to host, this is fed to Protocol_EnumForName
36 cvar_t sv_protocolname = {0, "sv_protocolname", "DP7", "selects network protocol to host for (values include QUAKE, QUAKEDP, NEHAHRAMOVIE, DP1 and up)"};
37 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)"};
38 cvar_t sv_maxrate = {CVAR_SAVE | CVAR_NOTIFY, "sv_maxrate", "10000", "upper limit on client rate cvar, should reflect your network connection quality"};
40 static cvar_t sv_cullentities_pvs = {0, "sv_cullentities_pvs", "1", "fast but loose culling of hidden entities"}; // fast but loose
41 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
42 static cvar_t sv_cullentities_stats = {0, "sv_cullentities_stats", "0", "displays stats on network entities culled by various methods for each client"};
43 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)"};
45 cvar_t sv_gameplayfix_grenadebouncedownslopes = {0, "sv_gameplayfix_grenadebouncedownslopes", "1", "prevents MOVETYPE_BOUNCE (grenades) from getting stuck when fired down a downward sloping surface"};
46 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"};
47 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)"};
48 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)"};
49 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"};
50 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"};
51 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"};
52 cvar_t sv_gameplayfix_findradiusdistancetobox = {0, "sv_gameplayfix_findradiusdistancetobox", "1", "causes findradius to check the distance to the corner of a box rather than the center of the box, makes findradius detect bmodels such as very large doors that would otherwise be unaffected by splash damage"};
53 cvar_t sv_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"};
55 cvar_t sv_progs = {0, "sv_progs", "progs.dat", "selects which quakec progs.dat file to run" };
57 // TODO: move these cvars here
58 extern cvar_t sv_clmovement_enable;
59 extern cvar_t sv_clmovement_minping;
60 extern cvar_t sv_clmovement_minping_disabletime;
61 extern cvar_t sv_clmovement_waitforinput;
66 mempool_t *sv_mempool = NULL;
68 //============================================================================
70 extern void SV_Phys_Init (void);
71 extern void SV_World_Init (void);
72 static void SV_SaveEntFile_f(void);
81 Cmd_AddCommand("sv_saveentfile", SV_SaveEntFile_f, "save map entities to .ent file (to allow external editing)");
82 Cvar_RegisterVariable (&sv_maxvelocity);
83 Cvar_RegisterVariable (&sv_gravity);
84 Cvar_RegisterVariable (&sv_friction);
85 Cvar_RegisterVariable (&sv_waterfriction);
86 Cvar_RegisterVariable (&sv_edgefriction);
87 Cvar_RegisterVariable (&sv_stopspeed);
88 Cvar_RegisterVariable (&sv_maxspeed);
89 Cvar_RegisterVariable (&sv_maxairspeed);
90 Cvar_RegisterVariable (&sv_accelerate);
91 Cvar_RegisterVariable (&sv_airaccelerate);
92 Cvar_RegisterVariable (&sv_wateraccelerate);
93 Cvar_RegisterVariable (&sv_clmovement_enable);
94 Cvar_RegisterVariable (&sv_clmovement_minping);
95 Cvar_RegisterVariable (&sv_clmovement_minping_disabletime);
96 Cvar_RegisterVariable (&sv_clmovement_waitforinput);
97 Cvar_RegisterVariable (&sv_idealpitchscale);
98 Cvar_RegisterVariable (&sv_aim);
99 Cvar_RegisterVariable (&sv_nostep);
100 Cvar_RegisterVariable (&sv_cullentities_pvs);
101 Cvar_RegisterVariable (&sv_cullentities_trace);
102 Cvar_RegisterVariable (&sv_cullentities_stats);
103 Cvar_RegisterVariable (&sv_entpatch);
104 Cvar_RegisterVariable (&sv_gameplayfix_grenadebouncedownslopes);
105 Cvar_RegisterVariable (&sv_gameplayfix_noairborncorpse);
106 Cvar_RegisterVariable (&sv_gameplayfix_stepdown);
107 Cvar_RegisterVariable (&sv_gameplayfix_stepwhilejumping);
108 Cvar_RegisterVariable (&sv_gameplayfix_swiminbmodels);
109 Cvar_RegisterVariable (&sv_gameplayfix_setmodelrealbox);
110 Cvar_RegisterVariable (&sv_gameplayfix_blowupfallenzombies);
111 Cvar_RegisterVariable (&sv_gameplayfix_findradiusdistancetobox);
112 Cvar_RegisterVariable (&sv_gameplayfix_qwplayerphysics);
113 Cvar_RegisterVariable (&sv_protocolname);
114 Cvar_RegisterVariable (&sv_ratelimitlocalplayer);
115 Cvar_RegisterVariable (&sv_maxrate);
116 Cvar_RegisterVariable (&sv_progs);
122 sv_mempool = Mem_AllocPool("server", 0, NULL);
125 static void SV_SaveEntFile_f(void)
127 char basename[MAX_QPATH];
128 if (!sv.active || !sv.worldmodel)
130 Con_Print("Not running a server\n");
133 FS_StripExtension(sv.worldmodel->name, basename, sizeof(basename));
134 FS_WriteFile(va("%s.ent", basename), sv.worldmodel->brush.entities, (fs_offset_t)strlen(sv.worldmodel->brush.entities));
139 =============================================================================
143 =============================================================================
150 Make sure the event gets sent to all clients
153 void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count)
157 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-18)
159 MSG_WriteByte (&sv.datagram, svc_particle);
160 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
161 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
162 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
163 for (i=0 ; i<3 ; i++)
164 MSG_WriteChar (&sv.datagram, (int)bound(-128, dir[i]*16, 127));
165 MSG_WriteByte (&sv.datagram, count);
166 MSG_WriteByte (&sv.datagram, color);
173 Make sure the event gets sent to all clients
176 void SV_StartEffect (vec3_t org, int modelindex, int startframe, int framecount, int framerate)
178 if (modelindex >= 256 || startframe >= 256)
180 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-19)
182 MSG_WriteByte (&sv.datagram, svc_effect2);
183 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
184 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
185 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
186 MSG_WriteShort (&sv.datagram, modelindex);
187 MSG_WriteShort (&sv.datagram, startframe);
188 MSG_WriteByte (&sv.datagram, framecount);
189 MSG_WriteByte (&sv.datagram, framerate);
193 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-17)
195 MSG_WriteByte (&sv.datagram, svc_effect);
196 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
197 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
198 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
199 MSG_WriteByte (&sv.datagram, modelindex);
200 MSG_WriteByte (&sv.datagram, startframe);
201 MSG_WriteByte (&sv.datagram, framecount);
202 MSG_WriteByte (&sv.datagram, framerate);
210 Each entity can have eight independant sound sources, like voice,
213 Channel 0 is an auto-allocate channel, the others override anything
214 already running on that entity/channel pair.
216 An attenuation of 0 will play full volume everywhere in the level.
217 Larger attenuations will drop off. (max 4 attenuation)
221 void SV_StartSound (prvm_edict_t *entity, int channel, const char *sample, int volume, float attenuation)
223 int sound_num, field_mask, i, ent;
225 if (volume < 0 || volume > 255)
227 Con_Printf ("SV_StartSound: volume = %i\n", volume);
231 if (attenuation < 0 || attenuation > 4)
233 Con_Printf ("SV_StartSound: attenuation = %f\n", attenuation);
237 if (channel < 0 || channel > 7)
239 Con_Printf ("SV_StartSound: channel = %i\n", channel);
243 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-21)
246 // find precache number for sound
247 sound_num = SV_SoundIndex(sample, 1);
251 ent = PRVM_NUM_FOR_EDICT(entity);
254 if (volume != DEFAULT_SOUND_PACKET_VOLUME)
255 field_mask |= SND_VOLUME;
256 if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
257 field_mask |= SND_ATTENUATION;
259 field_mask |= SND_LARGEENTITY;
260 if (sound_num >= 256 || channel >= 8)
261 field_mask |= SND_LARGESOUND;
263 // directed messages go only to the entity they are targeted on
264 MSG_WriteByte (&sv.datagram, svc_sound);
265 MSG_WriteByte (&sv.datagram, field_mask);
266 if (field_mask & SND_VOLUME)
267 MSG_WriteByte (&sv.datagram, volume);
268 if (field_mask & SND_ATTENUATION)
269 MSG_WriteByte (&sv.datagram, (int)(attenuation*64));
270 if (field_mask & SND_LARGEENTITY)
272 MSG_WriteShort (&sv.datagram, ent);
273 MSG_WriteByte (&sv.datagram, channel);
276 MSG_WriteShort (&sv.datagram, (ent<<3) | channel);
277 if (field_mask & SND_LARGESOUND)
278 MSG_WriteShort (&sv.datagram, sound_num);
280 MSG_WriteByte (&sv.datagram, sound_num);
281 for (i = 0;i < 3;i++)
282 MSG_WriteCoord (&sv.datagram, entity->fields.server->origin[i]+0.5*(entity->fields.server->mins[i]+entity->fields.server->maxs[i]), sv.protocol);
286 ==============================================================================
290 ==============================================================================
293 static const char *SV_InitCmd; //[515]: svprogs able to send cmd to client on connect
294 extern qboolean csqc_loaded;
299 Sends the first message from the server to a connected client.
300 This will be sent on the initial connection and upon each server load.
303 void SV_SendServerinfo (client_t *client)
308 // we know that this client has a netconnection and thus is not a bot
310 // edicts get reallocated on level changes, so we need to update it here
311 client->edict = PRVM_EDICT_NUM((client - svs.clients) + 1);
313 // clear cached stuff that depends on the level
314 client->weaponmodel[0] = 0;
315 client->weaponmodelindex = 0;
317 // LordHavoc: clear entityframe tracking
318 client->latestframenum = 0;
320 if (client->entitydatabase)
321 EntityFrame_FreeDatabase(client->entitydatabase);
322 if (client->entitydatabase4)
323 EntityFrame4_FreeDatabase(client->entitydatabase4);
324 if (client->entitydatabase5)
325 EntityFrame5_FreeDatabase(client->entitydatabase5);
327 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
329 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3)
330 client->entitydatabase = EntityFrame_AllocDatabase(sv_mempool);
331 else if (sv.protocol == PROTOCOL_DARKPLACES4)
332 client->entitydatabase4 = EntityFrame4_AllocDatabase(sv_mempool);
334 client->entitydatabase5 = EntityFrame5_AllocDatabase(sv_mempool);
337 SZ_Clear (&client->netconnection->message);
338 MSG_WriteByte (&client->netconnection->message, svc_print);
339 dpsnprintf (message, sizeof (message), "\nServer: %s build %s (progs %i crc)", gamename, buildstring, prog->filecrc);
340 MSG_WriteString (&client->netconnection->message,message);
342 // FIXME: LordHavoc: this does not work on dedicated servers, needs fixing.
343 //[515]: init csprogs according to version of svprogs, check the crc, etc.
344 if(csqc_loaded && (cls.state == ca_dedicated || PRVM_NUM_FOR_EDICT(client->edict) != 1))
346 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
348 MSG_WriteString (&client->netconnection->message, va("csqc_progcrc %i;%s\n", csqc_progcrc.integer, SV_InitCmd));
350 MSG_WriteString (&client->netconnection->message, va("csqc_progcrc %i\n", csqc_progcrc.integer));
353 MSG_WriteByte (&client->netconnection->message, svc_serverinfo);
354 MSG_WriteLong (&client->netconnection->message, Protocol_NumberForEnum(sv.protocol));
355 MSG_WriteByte (&client->netconnection->message, svs.maxclients);
357 if (!coop.integer && deathmatch.integer)
358 MSG_WriteByte (&client->netconnection->message, GAME_DEATHMATCH);
360 MSG_WriteByte (&client->netconnection->message, GAME_COOP);
362 MSG_WriteString (&client->netconnection->message,PRVM_GetString(prog->edicts->fields.server->message));
364 for (i = 1;i < MAX_MODELS && sv.model_precache[i][0];i++)
365 MSG_WriteString (&client->netconnection->message, sv.model_precache[i]);
366 MSG_WriteByte (&client->netconnection->message, 0);
368 for (i = 1;i < MAX_SOUNDS && sv.sound_precache[i][0];i++)
369 MSG_WriteString (&client->netconnection->message, sv.sound_precache[i]);
370 MSG_WriteByte (&client->netconnection->message, 0);
373 MSG_WriteByte (&client->netconnection->message, svc_cdtrack);
374 MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
375 MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
378 MSG_WriteByte (&client->netconnection->message, svc_setview);
379 MSG_WriteShort (&client->netconnection->message, PRVM_NUM_FOR_EDICT(client->edict));
381 MSG_WriteByte (&client->netconnection->message, svc_signonnum);
382 MSG_WriteByte (&client->netconnection->message, 1);
384 client->spawned = false; // need prespawn, spawn, etc
391 Initializes a client_t for a new net connection. This will only be called
392 once for a player each game, not once for each level change.
395 void SV_ConnectClient (int clientnum, netconn_t *netconnection)
399 float spawn_parms[NUM_SPAWN_PARMS];
401 client = svs.clients + clientnum;
403 if(netconnection)//[515]: bots don't play with csqc =)
404 EntityFrameCSQC_InitClientVersions(clientnum, false);
406 // set up the client_t
408 memcpy (spawn_parms, client->spawn_parms, sizeof(spawn_parms));
409 memset (client, 0, sizeof(*client));
410 client->active = true;
411 client->netconnection = netconnection;
413 Con_DPrintf("Client %s connected\n", client->netconnection ? client->netconnection->address : "botclient");
415 strcpy(client->name, "unconnected");
416 strcpy(client->old_name, "unconnected");
417 client->spawned = false;
418 client->edict = PRVM_EDICT_NUM(clientnum+1);
419 if (client->netconnection)
420 client->netconnection->message.allowoverflow = true; // we can catch it
421 // updated by receiving "rate" command from client
422 client->rate = NET_MINRATE;
423 // no limits for local player
424 if (client->netconnection && LHNETADDRESS_GetAddressType(&client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP)
425 client->rate = 1000000000;
426 client->connecttime = realtime;
429 memcpy (client->spawn_parms, spawn_parms, sizeof(spawn_parms));
432 // call the progs to get default spawn parms for the new client
433 // set self to world to intentionally cause errors with broken SetNewParms code in some mods
434 prog->globals.server->self = 0;
435 PRVM_ExecuteProgram (prog->globals.server->SetNewParms, "QC function SetNewParms is missing");
436 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
437 client->spawn_parms[i] = (&prog->globals.server->parm1)[i];
439 // set up the entity for this client (including .colormap, .team, etc)
440 PRVM_ED_ClearEdict(client->edict);
443 // don't call SendServerinfo for a fresh botclient because its fields have
444 // not been set up by the qc yet
445 if (client->netconnection)
446 SV_SendServerinfo (client);
448 client->spawned = true;
453 ===============================================================================
457 ===============================================================================
466 void SV_ClearDatagram (void)
468 SZ_Clear (&sv.datagram);
472 =============================================================================
474 The PVS must include a small area around the client to allow head bobbing
475 or other small motion on the client side. Otherwise, a bob might cause an
476 entity that should be visible to not show up, especially when the bob
479 =============================================================================
482 int sv_writeentitiestoclient_pvsbytes;
483 unsigned char sv_writeentitiestoclient_pvs[MAX_MAP_LEAFS/8];
485 static int numsendentities;
486 static entity_state_t sendentities[MAX_EDICTS];
487 static entity_state_t *sendentitiesindex[MAX_EDICTS];
489 qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *cs, int e)
492 unsigned int modelindex, effects, flags, glowsize, lightstyle, lightpflags, light[4], specialvisibilityradius;
493 unsigned int customizeentityforclient;
495 vec3_t cullmins, cullmaxs;
499 // EF_NODRAW prevents sending for any reason except for your own
500 // client, so we must keep all clients in this superset
501 effects = (unsigned)ent->fields.server->effects;
503 // we can omit invisible entities with no effects that are not clients
504 // LordHavoc: this could kill tags attached to an invisible entity, I
505 // just hope we never have to support that case
506 i = (int)ent->fields.server->modelindex;
507 modelindex = (i >= 1 && i < MAX_MODELS && *PRVM_GetString(ent->fields.server->model)) ? i : 0;
510 i = (int)(PRVM_GETEDICTFIELDVALUE(ent, eval_glow_size)->_float * 0.25f);
511 glowsize = (unsigned char)bound(0, i, 255);
512 if (PRVM_GETEDICTFIELDVALUE(ent, eval_glow_trail)->_float)
513 flags |= RENDER_GLOWTRAIL;
515 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[0]*256;
516 light[0] = (unsigned short)bound(0, f, 65535);
517 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[1]*256;
518 light[1] = (unsigned short)bound(0, f, 65535);
519 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[2]*256;
520 light[2] = (unsigned short)bound(0, f, 65535);
521 f = PRVM_GETEDICTFIELDVALUE(ent, eval_light_lev)->_float;
522 light[3] = (unsigned short)bound(0, f, 65535);
523 lightstyle = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_style)->_float;
524 lightpflags = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_pflags)->_float;
526 if (gamemode == GAME_TENEBRAE)
528 // tenebrae's EF_FULLDYNAMIC conflicts with Q2's EF_NODRAW
532 lightpflags |= PFLAGS_FULLDYNAMIC;
534 // tenebrae's EF_GREEN conflicts with DP's EF_ADDITIVE
538 light[0] = (int)(0.2*256);
539 light[1] = (int)(1.0*256);
540 light[2] = (int)(0.2*256);
542 lightpflags |= PFLAGS_FULLDYNAMIC;
546 specialvisibilityradius = 0;
547 if (lightpflags & PFLAGS_FULLDYNAMIC)
548 specialvisibilityradius = max(specialvisibilityradius, light[3]);
550 specialvisibilityradius = max(specialvisibilityradius, glowsize * 4);
551 if (flags & RENDER_GLOWTRAIL)
552 specialvisibilityradius = max(specialvisibilityradius, 100);
553 if (effects & (EF_BRIGHTFIELD | EF_MUZZLEFLASH | EF_BRIGHTLIGHT | EF_DIMLIGHT | EF_RED | EF_BLUE | EF_FLAME | EF_STARDUST))
555 if (effects & EF_BRIGHTFIELD)
556 specialvisibilityradius = max(specialvisibilityradius, 80);
557 if (effects & EF_MUZZLEFLASH)
558 specialvisibilityradius = max(specialvisibilityradius, 100);
559 if (effects & EF_BRIGHTLIGHT)
560 specialvisibilityradius = max(specialvisibilityradius, 400);
561 if (effects & EF_DIMLIGHT)
562 specialvisibilityradius = max(specialvisibilityradius, 200);
563 if (effects & EF_RED)
564 specialvisibilityradius = max(specialvisibilityradius, 200);
565 if (effects & EF_BLUE)
566 specialvisibilityradius = max(specialvisibilityradius, 200);
567 if (effects & EF_FLAME)
568 specialvisibilityradius = max(specialvisibilityradius, 250);
569 if (effects & EF_STARDUST)
570 specialvisibilityradius = max(specialvisibilityradius, 100);
573 // early culling checks
574 // (final culling is done by SV_MarkWriteEntityStateToClient)
575 customizeentityforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_customizeentityforclient)->function;
576 if (!customizeentityforclient)
578 if (e > svs.maxclients && (!modelindex && !specialvisibilityradius))
580 // this 2 billion unit check is actually to detect NAN origins
581 // (we really don't want to send those)
582 if (VectorLength2(ent->fields.server->origin) > 2000000000.0*2000000000.0)
590 VectorCopy(ent->fields.server->origin, cs->origin);
591 VectorCopy(ent->fields.server->angles, cs->angles);
593 cs->effects = effects;
594 cs->colormap = (unsigned)ent->fields.server->colormap;
595 cs->modelindex = modelindex;
596 cs->skin = (unsigned)ent->fields.server->skin;
597 cs->frame = (unsigned)ent->fields.server->frame;
598 cs->viewmodelforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)->edict;
599 cs->exteriormodelforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_exteriormodeltoclient)->edict;
600 cs->nodrawtoclient = PRVM_GETEDICTFIELDVALUE(ent, eval_nodrawtoclient)->edict;
601 cs->drawonlytoclient = PRVM_GETEDICTFIELDVALUE(ent, eval_drawonlytoclient)->edict;
602 cs->customizeentityforclient = customizeentityforclient;
603 cs->tagentity = PRVM_GETEDICTFIELDVALUE(ent, eval_tag_entity)->edict;
604 cs->tagindex = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_tag_index)->_float;
605 cs->glowsize = glowsize;
607 // don't need to init cs->colormod because the defaultstate did that for us
608 //cs->colormod[0] = cs->colormod[1] = cs->colormod[2] = 32;
609 val = PRVM_GETEDICTFIELDVALUE(ent, eval_colormod);
610 if (val->vector[0] || val->vector[1] || val->vector[2])
612 i = (int)(val->vector[0] * 32.0f);cs->colormod[0] = bound(0, i, 255);
613 i = (int)(val->vector[1] * 32.0f);cs->colormod[1] = bound(0, i, 255);
614 i = (int)(val->vector[2] * 32.0f);cs->colormod[2] = bound(0, i, 255);
617 cs->modelindex = modelindex;
620 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_alpha)->_float * 255.0f);
624 cs->alpha = (unsigned char)bound(0, i, 255);
627 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_renderamt)->_float);
631 cs->alpha = (unsigned char)bound(0, i, 255);
635 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_scale)->_float * 16.0f);
639 cs->scale = (unsigned char)bound(0, i, 255);
643 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_glow_color)->_float);
645 cs->glowcolor = (int)f;
647 if (PRVM_GETEDICTFIELDVALUE(ent, eval_fullbright)->_float)
648 cs->effects |= EF_FULLBRIGHT;
650 if (ent->fields.server->movetype == MOVETYPE_STEP)
651 cs->flags |= RENDER_STEP;
652 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)
653 cs->flags |= RENDER_LOWPRECISION;
654 if (ent->fields.server->colormap >= 1024)
655 cs->flags |= RENDER_COLORMAPPED;
656 if (cs->viewmodelforclient)
657 cs->flags |= RENDER_VIEWMODEL; // show relative to the view
659 cs->light[0] = light[0];
660 cs->light[1] = light[1];
661 cs->light[2] = light[2];
662 cs->light[3] = light[3];
663 cs->lightstyle = lightstyle;
664 cs->lightpflags = lightpflags;
666 cs->specialvisibilityradius = specialvisibilityradius;
668 // calculate the visible box of this entity (don't use the physics box
669 // as that is often smaller than a model, and would not count
670 // specialvisibilityradius)
671 if ((model = sv.models[modelindex]))
673 float scale = cs->scale * (1.0f / 16.0f);
674 if (cs->angles[0] || cs->angles[2]) // pitch and roll
676 VectorMA(cs->origin, scale, model->rotatedmins, cullmins);
677 VectorMA(cs->origin, scale, model->rotatedmaxs, cullmaxs);
679 else if (cs->angles[1])
681 VectorMA(cs->origin, scale, model->yawmins, cullmins);
682 VectorMA(cs->origin, scale, model->yawmaxs, cullmaxs);
686 VectorMA(cs->origin, scale, model->normalmins, cullmins);
687 VectorMA(cs->origin, scale, model->normalmaxs, cullmaxs);
692 // if there is no model (or it could not be loaded), use the physics box
693 VectorAdd(cs->origin, ent->fields.server->mins, cullmins);
694 VectorAdd(cs->origin, ent->fields.server->maxs, cullmaxs);
696 if (specialvisibilityradius)
698 cullmins[0] = min(cullmins[0], cs->origin[0] - specialvisibilityradius);
699 cullmins[1] = min(cullmins[1], cs->origin[1] - specialvisibilityradius);
700 cullmins[2] = min(cullmins[2], cs->origin[2] - specialvisibilityradius);
701 cullmaxs[0] = max(cullmaxs[0], cs->origin[0] + specialvisibilityradius);
702 cullmaxs[1] = max(cullmaxs[1], cs->origin[1] + specialvisibilityradius);
703 cullmaxs[2] = max(cullmaxs[2], cs->origin[2] + specialvisibilityradius);
705 if (!VectorCompare(cullmins, ent->priv.server->cullmins) || !VectorCompare(cullmaxs, ent->priv.server->cullmaxs))
707 VectorCopy(cullmins, ent->priv.server->cullmins);
708 VectorCopy(cullmaxs, ent->priv.server->cullmaxs);
709 ent->priv.server->pvs_numclusters = -1;
710 if (sv.worldmodel && sv.worldmodel->brush.FindBoxClusters)
712 i = sv.worldmodel->brush.FindBoxClusters(sv.worldmodel, cullmins, cullmaxs, MAX_ENTITYCLUSTERS, ent->priv.server->pvs_clusterlist);
713 if (i <= MAX_ENTITYCLUSTERS)
714 ent->priv.server->pvs_numclusters = i;
721 void SV_PrepareEntitiesForSending(void)
725 // send all entities that touch the pvs
727 sendentitiesindex[0] = NULL;
728 memset(sendentitiesindex, 0, prog->num_edicts * sizeof(entity_state_t *));
729 for (e = 1, ent = PRVM_NEXT_EDICT(prog->edicts);e < prog->num_edicts;e++, ent = PRVM_NEXT_EDICT(ent))
731 if (!ent->priv.server->free && SV_PrepareEntityForSending(ent, sendentities + numsendentities, e))
733 sendentitiesindex[e] = sendentities + numsendentities;
739 static int sententitiesmark = 0;
740 static int sententities[MAX_EDICTS];
741 static int sententitiesconsideration[MAX_EDICTS];
742 static int sv_writeentitiestoclient_culled_pvs;
743 static int sv_writeentitiestoclient_culled_trace;
744 static int sv_writeentitiestoclient_visibleentities;
745 static int sv_writeentitiestoclient_totalentities;
746 //static entity_frame_t sv_writeentitiestoclient_entityframe;
747 static int sv_writeentitiestoclient_clentnum;
748 static vec3_t sv_writeentitiestoclient_testeye;
749 static client_t *sv_writeentitiestoclient_client;
751 void SV_MarkWriteEntityStateToClient(entity_state_t *s)
758 if (sententitiesconsideration[s->number] == sententitiesmark)
760 sententitiesconsideration[s->number] = sententitiesmark;
761 sv_writeentitiestoclient_totalentities++;
763 if (s->customizeentityforclient)
765 prog->globals.server->self = s->number;
766 prog->globals.server->other = sv_writeentitiestoclient_clentnum;
767 PRVM_ExecuteProgram(s->customizeentityforclient, "customizeentityforclient: NULL function");
768 if(!PRVM_G_FLOAT(OFS_RETURN) || !SV_PrepareEntityForSending(PRVM_EDICT_NUM(s->number), s, s->number))
772 // never reject player
773 if (s->number != sv_writeentitiestoclient_clentnum)
775 // check various rejection conditions
776 if (s->nodrawtoclient == sv_writeentitiestoclient_clentnum)
778 if (s->drawonlytoclient && s->drawonlytoclient != sv_writeentitiestoclient_clentnum)
780 if (s->effects & EF_NODRAW)
782 // LordHavoc: only send entities with a model or important effects
783 if (!s->modelindex && s->specialvisibilityradius == 0)
786 // viewmodels don't have visibility checking
787 if (s->viewmodelforclient)
789 if (s->viewmodelforclient != sv_writeentitiestoclient_clentnum)
792 else if (s->tagentity)
794 // tag attached entities simply check their parent
795 if (!sendentitiesindex[s->tagentity])
797 SV_MarkWriteEntityStateToClient(sendentitiesindex[s->tagentity]);
798 if (sententities[s->tagentity] != sententitiesmark)
801 // always send world submodels in newer protocols because they don't
802 // generate much traffic (in old protocols they hog bandwidth)
803 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)))
805 // entity has survived every check so far, check if visible
806 ed = PRVM_EDICT_NUM(s->number);
808 // if not touching a visible leaf
809 if (sv_cullentities_pvs.integer && sv_writeentitiestoclient_pvsbytes)
811 if (ed->priv.server->pvs_numclusters < 0)
813 // entity too big for clusters list
814 if (sv.worldmodel && sv.worldmodel->brush.BoxTouchingPVS && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, sv_writeentitiestoclient_pvs, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
816 sv_writeentitiestoclient_culled_pvs++;
823 // check cached clusters list
824 for (i = 0;i < ed->priv.server->pvs_numclusters;i++)
825 if (CHECKPVSBIT(sv_writeentitiestoclient_pvs, ed->priv.server->pvs_clusterlist[i]))
827 if (i == ed->priv.server->pvs_numclusters)
829 sv_writeentitiestoclient_culled_pvs++;
835 // or not seen by random tracelines
836 if (sv_cullentities_trace.integer && !isbmodel)
838 // LordHavoc: test center first
839 testorigin[0] = (ed->priv.server->cullmins[0] + ed->priv.server->cullmaxs[0]) * 0.5f;
840 testorigin[1] = (ed->priv.server->cullmins[1] + ed->priv.server->cullmaxs[1]) * 0.5f;
841 testorigin[2] = (ed->priv.server->cullmins[2] + ed->priv.server->cullmaxs[2]) * 0.5f;
842 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
843 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
844 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
847 // LordHavoc: test random offsets, to maximize chance of detection
848 testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]);
849 testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]);
850 testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]);
851 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
852 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
853 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
856 if (s->specialvisibilityradius)
858 // LordHavoc: test random offsets, to maximize chance of detection
859 testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]);
860 testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]);
861 testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]);
862 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
863 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
864 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
868 if (realtime > sv_writeentitiestoclient_client->visibletime[s->number])
870 sv_writeentitiestoclient_culled_trace++;
877 // this just marks it for sending
878 // FIXME: it would be more efficient to send here, but the entity
879 // compressor isn't that flexible
880 sv_writeentitiestoclient_visibleentities++;
881 sententities[s->number] = sententitiesmark;
884 entity_state_t sendstates[MAX_EDICTS];
885 extern int csqc_clent;
887 void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t *msg, int *stats)
889 int i, numsendstates;
892 // if there isn't enough space to accomplish anything, skip it
893 if (msg->cursize + 25 > msg->maxsize)
896 sv_writeentitiestoclient_client = client;
898 sv_writeentitiestoclient_culled_pvs = 0;
899 sv_writeentitiestoclient_culled_trace = 0;
900 sv_writeentitiestoclient_visibleentities = 0;
901 sv_writeentitiestoclient_totalentities = 0;
903 // find the client's PVS
904 // the real place being tested from
905 VectorAdd(clent->fields.server->origin, clent->fields.server->view_ofs, sv_writeentitiestoclient_testeye);
906 sv_writeentitiestoclient_pvsbytes = 0;
907 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
908 sv_writeentitiestoclient_pvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, sv_writeentitiestoclient_testeye, 8, sv_writeentitiestoclient_pvs, sizeof(sv_writeentitiestoclient_pvs));
910 csqc_clent = sv_writeentitiestoclient_clentnum = PRVM_EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes
914 for (i = 0;i < numsendentities;i++)
915 SV_MarkWriteEntityStateToClient(sendentities + i);
918 for (i = 0;i < numsendentities;i++)
920 if (sententities[sendentities[i].number] == sententitiesmark)
922 s = &sendstates[numsendstates++];
923 *s = sendentities[i];
924 if (s->exteriormodelforclient && s->exteriormodelforclient == sv_writeentitiestoclient_clentnum)
925 s->flags |= RENDER_EXTERIORMODEL;
929 if (sv_cullentities_stats.integer)
930 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);
932 EntityFrameCSQC_WriteFrame(msg, numsendstates, sendstates);
934 if (client->entitydatabase5)
935 EntityFrame5_WriteFrame(msg, client->entitydatabase5, numsendstates, sendstates, client - svs.clients + 1, stats, client->movesequence);
936 else if (client->entitydatabase4)
937 EntityFrame4_WriteFrame(msg, client->entitydatabase4, numsendstates, sendstates);
938 else if (client->entitydatabase)
939 EntityFrame_WriteFrame(msg, client->entitydatabase, numsendstates, sendstates, client - svs.clients + 1);
941 EntityFrameQuake_WriteFrame(msg, numsendstates, sendstates);
950 void SV_CleanupEnts (void)
955 ent = PRVM_NEXT_EDICT(prog->edicts);
956 for (e=1 ; e<prog->num_edicts ; e++, ent = PRVM_NEXT_EDICT(ent))
957 ent->fields.server->effects = (int)ent->fields.server->effects & ~EF_MUZZLEFLASH;
962 SV_WriteClientdataToMessage
966 void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
978 // send a damage message
980 if (ent->fields.server->dmg_take || ent->fields.server->dmg_save)
982 other = PRVM_PROG_TO_EDICT(ent->fields.server->dmg_inflictor);
983 MSG_WriteByte (msg, svc_damage);
984 MSG_WriteByte (msg, (int)ent->fields.server->dmg_save);
985 MSG_WriteByte (msg, (int)ent->fields.server->dmg_take);
986 for (i=0 ; i<3 ; i++)
987 MSG_WriteCoord (msg, other->fields.server->origin[i] + 0.5*(other->fields.server->mins[i] + other->fields.server->maxs[i]), sv.protocol);
989 ent->fields.server->dmg_take = 0;
990 ent->fields.server->dmg_save = 0;
994 // send the current viewpos offset from the view entity
996 SV_SetIdealPitch (); // how much to look up / down ideally
998 // a fixangle might get lost in a dropped packet. Oh well.
999 if ( ent->fields.server->fixangle )
1001 MSG_WriteByte (msg, svc_setangle);
1002 for (i=0 ; i < 3 ; i++)
1003 MSG_WriteAngle (msg, ent->fields.server->angles[i], sv.protocol);
1004 ent->fields.server->fixangle = 0;
1007 // stuff the sigil bits into the high bits of items for sbar, or else
1009 val = PRVM_GETEDICTFIELDVALUE(ent, eval_items2);
1010 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
1011 items = (int)ent->fields.server->items | ((int)val->_float << 23);
1013 items = (int)ent->fields.server->items | ((int)prog->globals.server->serverflags << 28);
1015 VectorClear(punchvector);
1016 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_punchvector)))
1017 VectorCopy(val->vector, punchvector);
1019 // cache weapon model name and index in client struct to save time
1020 // (this search can be almost 1% of cpu time!)
1021 s = PRVM_GetString(ent->fields.server->weaponmodel);
1022 if (strcmp(s, client->weaponmodel))
1024 strlcpy(client->weaponmodel, s, sizeof(client->weaponmodel));
1025 client->weaponmodelindex = SV_ModelIndex(s, 1);
1029 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_viewzoom)))
1030 viewzoom = (int)(val->_float * 255.0f);
1036 if ((int)ent->fields.server->flags & FL_ONGROUND)
1037 bits |= SU_ONGROUND;
1038 if (ent->fields.server->waterlevel >= 2)
1040 if (ent->fields.server->idealpitch)
1041 bits |= SU_IDEALPITCH;
1043 for (i=0 ; i<3 ; i++)
1045 if (ent->fields.server->punchangle[i])
1046 bits |= (SU_PUNCH1<<i);
1047 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
1049 bits |= (SU_PUNCHVEC1<<i);
1050 if (ent->fields.server->velocity[i])
1051 bits |= (SU_VELOCITY1<<i);
1054 memset(stats, 0, sizeof(int[MAX_CL_STATS]));
1055 stats[STAT_VIEWHEIGHT] = (int)ent->fields.server->view_ofs[2];
1056 stats[STAT_ITEMS] = items;
1057 stats[STAT_WEAPONFRAME] = (int)ent->fields.server->weaponframe;
1058 stats[STAT_ARMOR] = (int)ent->fields.server->armorvalue;
1059 stats[STAT_WEAPON] = client->weaponmodelindex;
1060 stats[STAT_HEALTH] = (int)ent->fields.server->health;
1061 stats[STAT_AMMO] = (int)ent->fields.server->currentammo;
1062 stats[STAT_SHELLS] = (int)ent->fields.server->ammo_shells;
1063 stats[STAT_NAILS] = (int)ent->fields.server->ammo_nails;
1064 stats[STAT_ROCKETS] = (int)ent->fields.server->ammo_rockets;
1065 stats[STAT_CELLS] = (int)ent->fields.server->ammo_cells;
1066 stats[STAT_ACTIVEWEAPON] = (int)ent->fields.server->weapon;
1067 stats[STAT_VIEWZOOM] = viewzoom;
1068 // the QC bumps these itself by sending svc_'s, so we have to keep them
1069 // zero or they'll be corrected by the engine
1070 //stats[STAT_TOTALSECRETS] = prog->globals.server->total_secrets;
1071 //stats[STAT_TOTALMONSTERS] = prog->globals.server->total_monsters;
1072 //stats[STAT_SECRETS] = prog->globals.server->found_secrets;
1073 //stats[STAT_MONSTERS] = prog->globals.server->killed_monsters;
1075 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)
1077 if (stats[STAT_VIEWHEIGHT] != DEFAULT_VIEWHEIGHT) bits |= SU_VIEWHEIGHT;
1079 if (stats[STAT_WEAPONFRAME]) bits |= SU_WEAPONFRAME;
1080 if (stats[STAT_ARMOR]) bits |= SU_ARMOR;
1082 // FIXME: which protocols support this? does PROTOCOL_DARKPLACES3 support viewzoom?
1083 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
1084 if (viewzoom != 255)
1085 bits |= SU_VIEWZOOM;
1090 if (bits >= 16777216)
1094 MSG_WriteByte (msg, svc_clientdata);
1095 MSG_WriteShort (msg, bits);
1096 if (bits & SU_EXTEND1)
1097 MSG_WriteByte(msg, bits >> 16);
1098 if (bits & SU_EXTEND2)
1099 MSG_WriteByte(msg, bits >> 24);
1101 if (bits & SU_VIEWHEIGHT)
1102 MSG_WriteChar (msg, stats[STAT_VIEWHEIGHT]);
1104 if (bits & SU_IDEALPITCH)
1105 MSG_WriteChar (msg, (int)ent->fields.server->idealpitch);
1107 for (i=0 ; i<3 ; i++)
1109 if (bits & (SU_PUNCH1<<i))
1111 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1112 MSG_WriteChar(msg, (int)ent->fields.server->punchangle[i]);
1114 MSG_WriteAngle16i(msg, ent->fields.server->punchangle[i]);
1116 if (bits & (SU_PUNCHVEC1<<i))
1118 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1119 MSG_WriteCoord16i(msg, punchvector[i]);
1121 MSG_WriteCoord32f(msg, punchvector[i]);
1123 if (bits & (SU_VELOCITY1<<i))
1125 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1126 MSG_WriteChar(msg, (int)(ent->fields.server->velocity[i] * (1.0f / 16.0f)));
1128 MSG_WriteCoord32f(msg, ent->fields.server->velocity[i]);
1132 if (bits & SU_ITEMS)
1133 MSG_WriteLong (msg, stats[STAT_ITEMS]);
1135 if (sv.protocol == PROTOCOL_DARKPLACES5)
1137 if (bits & SU_WEAPONFRAME)
1138 MSG_WriteShort (msg, stats[STAT_WEAPONFRAME]);
1139 if (bits & SU_ARMOR)
1140 MSG_WriteShort (msg, stats[STAT_ARMOR]);
1141 if (bits & SU_WEAPON)
1142 MSG_WriteShort (msg, stats[STAT_WEAPON]);
1143 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1144 MSG_WriteShort (msg, stats[STAT_AMMO]);
1145 MSG_WriteShort (msg, stats[STAT_SHELLS]);
1146 MSG_WriteShort (msg, stats[STAT_NAILS]);
1147 MSG_WriteShort (msg, stats[STAT_ROCKETS]);
1148 MSG_WriteShort (msg, stats[STAT_CELLS]);
1149 MSG_WriteShort (msg, stats[STAT_ACTIVEWEAPON]);
1150 if (bits & SU_VIEWZOOM)
1151 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1153 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)
1155 if (bits & SU_WEAPONFRAME)
1156 MSG_WriteByte (msg, stats[STAT_WEAPONFRAME]);
1157 if (bits & SU_ARMOR)
1158 MSG_WriteByte (msg, stats[STAT_ARMOR]);
1159 if (bits & SU_WEAPON)
1160 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1161 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1162 MSG_WriteByte (msg, stats[STAT_AMMO]);
1163 MSG_WriteByte (msg, stats[STAT_SHELLS]);
1164 MSG_WriteByte (msg, stats[STAT_NAILS]);
1165 MSG_WriteByte (msg, stats[STAT_ROCKETS]);
1166 MSG_WriteByte (msg, stats[STAT_CELLS]);
1167 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_NEXUIZ)
1169 for (i = 0;i < 32;i++)
1170 if (stats[STAT_WEAPON] & (1<<i))
1172 MSG_WriteByte (msg, i);
1175 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1176 if (bits & SU_VIEWZOOM)
1178 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1179 MSG_WriteByte (msg, bound(0, stats[STAT_VIEWZOOM], 255));
1181 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1187 =======================
1188 SV_SendClientDatagram
1189 =======================
1191 static unsigned char sv_sendclientdatagram_buf[NET_MAXMESSAGE]; // FIXME?
1192 void SV_SendClientDatagram (client_t *client)
1194 int rate, maxrate, maxsize, maxsize2;
1196 int stats[MAX_CL_STATS];
1198 if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP && !sv_ratelimitlocalplayer.integer)
1200 // for good singleplayer, send huge packets
1201 maxsize = sizeof(sv_sendclientdatagram_buf);
1202 maxsize2 = sizeof(sv_sendclientdatagram_buf);
1204 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)
1206 // no rate limiting support on older protocols because dp protocols
1207 // 1-4 kick the client off if they overflow, and quake protocol shows
1208 // less than the full entity set if rate limited
1214 // PROTOCOL_DARKPLACES5 and later support packet size limiting of updates
1215 maxrate = bound(NET_MINRATE, sv_maxrate.integer, NET_MAXRATE);
1216 if (sv_maxrate.integer != maxrate)
1217 Cvar_SetValueQuick(&sv_maxrate, maxrate);
1219 // this rate limiting does not understand sys_ticrate 0
1220 // (but no one should be running that on a server!)
1221 rate = bound(NET_MINRATE, client->rate, maxrate);
1222 rate = (int)(client->rate * sys_ticrate.value);
1223 maxsize = bound(100, rate, 1400);
1227 msg.data = sv_sendclientdatagram_buf;
1228 msg.maxsize = maxsize;
1231 if (host_client->spawned)
1233 MSG_WriteByte (&msg, svc_time);
1234 MSG_WriteFloat (&msg, sv.time);
1236 // add the client specific data to the datagram
1237 SV_WriteClientdataToMessage (client, client->edict, &msg, stats);
1238 VM_SV_WriteAutoSentStats (client, client->edict, &msg, stats);
1239 SV_WriteEntitiesToClient (client, client->edict, &msg, stats);
1241 // expand packet size to allow effects to go over the rate limit
1242 // (dropping them is FAR too ugly)
1243 msg.maxsize = maxsize2;
1245 // copy the server datagram if there is space
1246 // FIXME: put in delayed queue of effects to send
1247 if (sv.datagram.cursize > 0 && msg.cursize + sv.datagram.cursize <= msg.maxsize)
1248 SZ_Write (&msg, sv.datagram.data, sv.datagram.cursize);
1250 else if (realtime > client->keepalivetime)
1252 // the player isn't totally in the game yet
1253 // send small keepalive messages if too much time has passed
1254 client->keepalivetime = realtime + 5;
1255 MSG_WriteChar (&msg, svc_nop);
1258 // send the datagram
1259 NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol);
1263 =======================
1264 SV_UpdateToReliableMessages
1265 =======================
1267 void SV_UpdateToReliableMessages (void)
1276 // check for changes to be sent over the reliable streams
1277 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1279 // update the host_client fields we care about according to the entity fields
1280 host_client->edict = PRVM_EDICT_NUM(i+1);
1283 name = PRVM_GetString(host_client->edict->fields.server->netname);
1286 // always point the string back at host_client->name to keep it safe
1287 strlcpy (host_client->name, name, sizeof (host_client->name));
1288 host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
1289 if (strcmp(host_client->old_name, host_client->name))
1291 if (host_client->spawned)
1292 SV_BroadcastPrintf("%s changed name to %s\n", host_client->old_name, host_client->name);
1293 strcpy(host_client->old_name, host_client->name);
1294 // send notification to all clients
1295 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
1296 MSG_WriteByte (&sv.reliable_datagram, i);
1297 MSG_WriteString (&sv.reliable_datagram, host_client->name);
1300 // DP_SV_CLIENTCOLORS
1301 // this is always found (since it's added by the progs loader)
1302 if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_clientcolors)))
1303 host_client->colors = (int)val->_float;
1304 if (host_client->old_colors != host_client->colors)
1306 host_client->old_colors = host_client->colors;
1307 // send notification to all clients
1308 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1309 MSG_WriteByte (&sv.reliable_datagram, i);
1310 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1313 // NEXUIZ_PLAYERMODEL
1314 if( eval_playermodel ) {
1315 model = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string);
1318 // always point the string back at host_client->name to keep it safe
1319 strlcpy (host_client->playermodel, model, sizeof (host_client->playermodel));
1320 PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
1323 // NEXUIZ_PLAYERSKIN
1324 if( eval_playerskin ) {
1325 skin = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string);
1328 // always point the string back at host_client->name to keep it safe
1329 strlcpy (host_client->playerskin, skin, sizeof (host_client->playerskin));
1330 PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
1334 host_client->frags = (int)host_client->edict->fields.server->frags;
1335 if (host_client->old_frags != host_client->frags)
1337 host_client->old_frags = host_client->frags;
1338 // send notification to all clients
1339 MSG_WriteByte (&sv.reliable_datagram, svc_updatefrags);
1340 MSG_WriteByte (&sv.reliable_datagram, i);
1341 MSG_WriteShort (&sv.reliable_datagram, host_client->frags);
1345 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1346 if (client->netconnection)
1347 SZ_Write (&client->netconnection->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
1349 SZ_Clear (&sv.reliable_datagram);
1354 =======================
1355 SV_SendClientMessages
1356 =======================
1358 void SV_SendClientMessages (void)
1360 int i, prepared = false;
1362 if (sv.protocol == PROTOCOL_QUAKEWORLD)
1363 Sys_Error("SV_SendClientMessages: no quakeworld support\n");
1365 // update frags, names, etc
1366 SV_UpdateToReliableMessages();
1368 // build individual updates
1369 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1371 if (!host_client->active)
1373 if (!host_client->netconnection)
1376 if (host_client->netconnection->message.overflowed)
1378 SV_DropClient (true); // if the message couldn't send, kick off
1385 // only prepare entities once per frame
1386 SV_PrepareEntitiesForSending();
1388 SV_SendClientDatagram (host_client);
1391 // clear muzzle flashes
1397 ==============================================================================
1401 ==============================================================================
1410 int SV_ModelIndex(const char *s, int precachemode)
1412 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_MODELS);
1413 char filename[MAX_QPATH];
1417 //if (precachemode == 2)
1419 strlcpy(filename, s, sizeof(filename));
1420 for (i = 2;i < limit;i++)
1422 if (!sv.model_precache[i][0])
1426 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))
1428 Con_Printf("SV_ModelIndex(\"%s\"): precache_model can only be done in spawn functions\n", filename);
1431 if (precachemode == 1)
1432 Con_Printf("SV_ModelIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1433 strlcpy(sv.model_precache[i], filename, sizeof(sv.model_precache[i]));
1434 sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, false);
1435 if (sv.state != ss_loading)
1437 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1438 MSG_WriteShort(&sv.reliable_datagram, i);
1439 MSG_WriteString(&sv.reliable_datagram, filename);
1443 Con_Printf("SV_ModelIndex(\"%s\"): not precached\n", filename);
1446 if (!strcmp(sv.model_precache[i], filename))
1449 Con_Printf("SV_ModelIndex(\"%s\"): i (%i) == MAX_MODELS (%i)\n", filename, i, MAX_MODELS);
1459 int SV_SoundIndex(const char *s, int precachemode)
1461 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_SOUNDS);
1462 char filename[MAX_QPATH];
1466 //if (precachemode == 2)
1468 strlcpy(filename, s, sizeof(filename));
1469 for (i = 1;i < limit;i++)
1471 if (!sv.sound_precache[i][0])
1475 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))
1477 Con_Printf("SV_SoundIndex(\"%s\"): precache_sound can only be done in spawn functions\n", filename);
1480 if (precachemode == 1)
1481 Con_Printf("SV_SoundIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1482 strlcpy(sv.sound_precache[i], filename, sizeof(sv.sound_precache[i]));
1483 if (sv.state != ss_loading)
1485 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1486 MSG_WriteShort(&sv.reliable_datagram, i + 32768);
1487 MSG_WriteString(&sv.reliable_datagram, filename);
1491 Con_Printf("SV_SoundIndex(\"%s\"): not precached\n", filename);
1494 if (!strcmp(sv.sound_precache[i], filename))
1497 Con_Printf("SV_SoundIndex(\"%s\"): i (%i) == MAX_SOUNDS (%i)\n", filename, i, MAX_SOUNDS);
1507 void SV_CreateBaseline (void)
1509 int i, entnum, large;
1510 prvm_edict_t *svent;
1512 // LordHavoc: clear *all* states (note just active ones)
1513 for (entnum = 0;entnum < prog->max_edicts;entnum++)
1515 // get the current server version
1516 svent = PRVM_EDICT_NUM(entnum);
1518 // LordHavoc: always clear state values, whether the entity is in use or not
1519 svent->priv.server->baseline = defaultstate;
1521 if (svent->priv.server->free)
1523 if (entnum > svs.maxclients && !svent->fields.server->modelindex)
1526 // create entity baseline
1527 VectorCopy (svent->fields.server->origin, svent->priv.server->baseline.origin);
1528 VectorCopy (svent->fields.server->angles, svent->priv.server->baseline.angles);
1529 svent->priv.server->baseline.frame = (int)svent->fields.server->frame;
1530 svent->priv.server->baseline.skin = (int)svent->fields.server->skin;
1531 if (entnum > 0 && entnum <= svs.maxclients)
1533 svent->priv.server->baseline.colormap = entnum;
1534 svent->priv.server->baseline.modelindex = SV_ModelIndex("progs/player.mdl", 1);
1538 svent->priv.server->baseline.colormap = 0;
1539 svent->priv.server->baseline.modelindex = (int)svent->fields.server->modelindex;
1543 if (svent->priv.server->baseline.modelindex & 0xFF00 || svent->priv.server->baseline.frame & 0xFF00)
1546 // add to the message
1548 MSG_WriteByte (&sv.signon, svc_spawnbaseline2);
1550 MSG_WriteByte (&sv.signon, svc_spawnbaseline);
1551 MSG_WriteShort (&sv.signon, entnum);
1555 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.modelindex);
1556 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.frame);
1560 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.modelindex);
1561 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.frame);
1563 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.colormap);
1564 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.skin);
1565 for (i=0 ; i<3 ; i++)
1567 MSG_WriteCoord(&sv.signon, svent->priv.server->baseline.origin[i], sv.protocol);
1568 MSG_WriteAngle(&sv.signon, svent->priv.server->baseline.angles[i], sv.protocol);
1578 Grabs the current state of each client for saving across the
1579 transition to another level
1582 void SV_SaveSpawnparms (void)
1586 svs.serverflags = (int)prog->globals.server->serverflags;
1588 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1590 if (!host_client->active)
1593 // call the progs to get default spawn parms for the new client
1594 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1595 PRVM_ExecuteProgram (prog->globals.server->SetChangeParms, "QC function SetChangeParms is missing");
1596 for (j=0 ; j<NUM_SPAWN_PARMS ; j++)
1597 host_client->spawn_parms[j] = (&prog->globals.server->parm1)[j];
1601 void SV_IncreaseEdicts(void)
1605 int oldmax_edicts = prog->max_edicts;
1606 void *oldedictsengineprivate = prog->edictprivate;
1607 void *oldedictsfields = prog->edictsfields;
1608 void *oldmoved_edicts = sv.moved_edicts;
1610 if (prog->max_edicts >= MAX_EDICTS)
1613 // links don't survive the transition, so unlink everything
1614 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1616 if (!ent->priv.server->free)
1617 SV_UnlinkEdict(prog->edicts + i);
1618 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
1622 prog->max_edicts = min(prog->max_edicts + 256, MAX_EDICTS);
1623 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
1624 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);
1625 sv.moved_edicts = PR_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1627 memcpy(prog->edictprivate, oldedictsengineprivate, oldmax_edicts * sizeof(edict_engineprivate_t));
1628 memcpy(prog->edictsfields, oldedictsfields, oldmax_edicts * prog->edict_size);
1630 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1632 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
1633 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
1634 // link every entity except world
1635 if (!ent->priv.server->free)
1636 SV_LinkEdict(ent, false);
1639 PR_Free(oldedictsengineprivate);
1640 PR_Free(oldedictsfields);
1641 PR_Free(oldmoved_edicts);
1648 This is called at the start of each level
1651 extern float scr_centertime_off;
1653 void SV_SpawnServer (const char *server)
1658 model_t *worldmodel;
1659 char modelname[sizeof(sv.modelname)];
1661 Con_DPrintf("SpawnServer: %s\n", server);
1663 if (cls.state != ca_dedicated)
1664 SCR_BeginLoadingPlaque();
1666 dpsnprintf (modelname, sizeof(modelname), "maps/%s.bsp", server);
1667 worldmodel = Mod_ForName(modelname, false, true, true);
1668 if (!worldmodel || !worldmodel->TraceBox)
1670 Con_Printf("Couldn't load map %s\n", modelname);
1674 // let's not have any servers with no name
1675 if (hostname.string[0] == 0)
1676 Cvar_Set ("hostname", "UNNAMED");
1677 scr_centertime_off = 0;
1679 svs.changelevel_issued = false; // now safe to issue another
1681 // make the map a required file for clients
1682 Curl_ClearRequirements();
1683 Curl_RequireFile(modelname);
1686 // tell all connected clients that we are going to a new level
1691 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
1693 if (client->netconnection)
1695 MSG_WriteByte(&client->netconnection->message, svc_stufftext);
1696 MSG_WriteString(&client->netconnection->message, "reconnect\n");
1703 NetConn_OpenServerPorts(true);
1707 // make cvars consistant
1710 Cvar_SetValue ("deathmatch", 0);
1711 // LordHavoc: it can be useful to have skills outside the range 0-3...
1712 //current_skill = bound(0, (int)(skill.value + 0.5), 3);
1713 //Cvar_SetValue ("skill", (float)current_skill);
1714 current_skill = (int)(skill.value + 0.5);
1717 // set up the new server
1719 memset (&sv, 0, sizeof(sv));
1720 // if running a local client, make sure it doesn't try to access the last
1721 // level's data which is no longer valiud
1728 strlcpy (sv.name, server, sizeof (sv.name));
1730 sv.protocol = Protocol_EnumForName(sv_protocolname.string);
1731 if (sv.protocol == PROTOCOL_UNKNOWN)
1734 Protocol_Names(buffer, sizeof(buffer));
1735 Con_Printf("Unknown sv_protocolname \"%s\", valid values are:\n%s\n", sv_protocolname.string, buffer);
1736 sv.protocol = PROTOCOL_QUAKE;
1741 // load progs to get entity field count
1742 //PR_LoadProgs ( sv_progs.string );
1744 // allocate server memory
1745 /*// start out with just enough room for clients and a reasonable estimate of entities
1746 prog->max_edicts = max(svs.maxclients + 1, 512);
1747 prog->max_edicts = min(prog->max_edicts, MAX_EDICTS);
1749 // prvm_edict_t structures (hidden from progs)
1750 prog->edicts = PR_Alloc(MAX_EDICTS * sizeof(prvm_edict_t));
1751 // engine private structures (hidden from progs)
1752 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
1753 // progs fields, often accessed by server
1754 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);*/
1755 // used by PushMove to move back pushed entities
1756 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1757 /*for (i = 0;i < prog->max_edicts;i++)
1759 ent = prog->edicts + i;
1760 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
1761 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
1764 // reset client csqc entity versions right away.
1765 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1766 EntityFrameCSQC_InitClientVersions(i, true);
1768 sv.datagram.maxsize = sizeof(sv.datagram_buf);
1769 sv.datagram.cursize = 0;
1770 sv.datagram.data = sv.datagram_buf;
1772 sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf);
1773 sv.reliable_datagram.cursize = 0;
1774 sv.reliable_datagram.data = sv.reliable_datagram_buf;
1776 sv.signon.maxsize = sizeof(sv.signon_buf);
1777 sv.signon.cursize = 0;
1778 sv.signon.data = sv.signon_buf;
1780 // leave slots at start for clients only
1781 //prog->num_edicts = svs.maxclients+1;
1783 sv.state = ss_loading;
1784 prog->allowworldwrites = true;
1787 *prog->time = sv.time = 1.0;
1790 worldmodel->used = true;
1792 strlcpy (sv.name, server, sizeof (sv.name));
1793 strcpy(sv.modelname, modelname);
1794 sv.worldmodel = worldmodel;
1795 sv.models[1] = sv.worldmodel;
1798 // clear world interaction links
1802 strlcpy(sv.sound_precache[0], "", sizeof(sv.sound_precache[0]));
1804 strlcpy(sv.model_precache[0], "", sizeof(sv.model_precache[0]));
1805 strlcpy(sv.model_precache[1], sv.modelname, sizeof(sv.model_precache[1]));
1806 for (i = 1;i < sv.worldmodel->brush.numsubmodels;i++)
1808 dpsnprintf(sv.model_precache[i+1], sizeof(sv.model_precache[i+1]), "*%i", i);
1809 sv.models[i+1] = Mod_ForName (sv.model_precache[i+1], false, false, false);
1813 // load the rest of the entities
1815 // AK possible hack since num_edicts is still 0
1816 ent = PRVM_EDICT_NUM(0);
1817 memset (ent->fields.server, 0, prog->progs->entityfields * 4);
1818 ent->priv.server->free = false;
1819 ent->fields.server->model = PRVM_SetEngineString(sv.modelname);
1820 ent->fields.server->modelindex = 1; // world model
1821 ent->fields.server->solid = SOLID_BSP;
1822 ent->fields.server->movetype = MOVETYPE_PUSH;
1825 prog->globals.server->coop = coop.integer;
1827 prog->globals.server->deathmatch = deathmatch.integer;
1829 prog->globals.server->mapname = PRVM_SetEngineString(sv.name);
1831 // serverflags are for cross level information (sigils)
1832 prog->globals.server->serverflags = svs.serverflags;
1834 // we need to reset the spawned flag on all connected clients here so that
1835 // their thinks don't run during startup (before PutClientInServer)
1836 // we also need to set up the client entities now
1837 // and we need to set the ->edict pointers to point into the progs edicts
1838 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1840 host_client->spawned = false;
1841 host_client->edict = PRVM_EDICT_NUM(i + 1);
1842 PRVM_ED_ClearEdict(host_client->edict);
1845 // load replacement entity file if found
1846 if (sv_entpatch.integer && (entities = (char *)FS_LoadFile(va("maps/%s.ent", sv.name), tempmempool, true, NULL)))
1848 Con_Printf("Loaded maps/%s.ent\n", sv.name);
1849 PRVM_ED_LoadFromFile (entities);
1853 PRVM_ED_LoadFromFile (sv.worldmodel->brush.entities);
1856 // LordHavoc: clear world angles (to fix e3m3.bsp)
1857 VectorClear(prog->edicts->fields.server->angles);
1859 // all setup is completed, any further precache statements are errors
1860 sv.state = ss_active;
1861 prog->allowworldwrites = false;
1863 // run two frames to allow everything to settle
1864 for (i = 0;i < 2;i++)
1872 // create a baseline for more efficient communications
1873 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1874 SV_CreateBaseline ();
1876 // send serverinfo to all connected clients, and set up botclients coming back from a level change
1877 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1879 if (!host_client->active)
1881 if (host_client->netconnection)
1882 SV_SendServerinfo(host_client);
1886 // if client is a botclient coming from a level change, we need to
1887 // set up client info that normally requires networking
1889 // copy spawn parms out of the client_t
1890 for (j=0 ; j< NUM_SPAWN_PARMS ; j++)
1891 (&prog->globals.server->parm1)[j] = host_client->spawn_parms[j];
1893 // call the spawn function
1894 host_client->clientconnectcalled = true;
1895 prog->globals.server->time = sv.time;
1896 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1897 PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
1898 PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
1899 host_client->spawned = true;
1903 Con_DPrint("Server spawned.\n");
1904 NetConn_Heartbeat (2);
1909 /////////////////////////////////////////////////////
1912 void SV_VM_CB_BeginIncreaseEdicts(void)
1917 PRVM_Free( sv.moved_edicts );
1918 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1920 // links don't survive the transition, so unlink everything
1921 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1923 if (!ent->priv.server->free)
1924 SV_UnlinkEdict(prog->edicts + i);
1925 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
1930 void SV_VM_CB_EndIncreaseEdicts(void)
1935 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1937 // link every entity except world
1938 if (!ent->priv.server->free)
1939 SV_LinkEdict(ent, false);
1943 void SV_VM_CB_InitEdict(prvm_edict_t *e)
1945 // LordHavoc: for consistency set these here
1946 int num = PRVM_NUM_FOR_EDICT(e) - 1;
1948 e->priv.server->move = false; // don't move on first frame
1950 if (num >= 0 && num < svs.maxclients)
1953 // set colormap and team on newly created player entity
1954 e->fields.server->colormap = num + 1;
1955 e->fields.server->team = (svs.clients[num].colors & 15) + 1;
1956 // set netname/clientcolors back to client values so that
1957 // DP_SV_CLIENTNAME and DP_SV_CLIENTCOLORS will not immediately
1959 e->fields.server->netname = PRVM_SetEngineString(svs.clients[num].name);
1960 if ((val = PRVM_GETEDICTFIELDVALUE(e, eval_clientcolors)))
1961 val->_float = svs.clients[num].colors;
1962 // NEXUIZ_PLAYERMODEL and NEXUIZ_PLAYERSKIN
1963 if( eval_playermodel )
1964 PRVM_GETEDICTFIELDVALUE(e, eval_playermodel)->string = PRVM_SetEngineString(svs.clients[num].playermodel);
1965 if( eval_playerskin )
1966 PRVM_GETEDICTFIELDVALUE(e, eval_playerskin)->string = PRVM_SetEngineString(svs.clients[num].playerskin);
1970 void SV_VM_CB_FreeEdict(prvm_edict_t *ed)
1972 SV_UnlinkEdict (ed); // unlink from world bsp
1974 ed->fields.server->model = 0;
1975 ed->fields.server->takedamage = 0;
1976 ed->fields.server->modelindex = 0;
1977 ed->fields.server->colormap = 0;
1978 ed->fields.server->skin = 0;
1979 ed->fields.server->frame = 0;
1980 VectorClear(ed->fields.server->origin);
1981 VectorClear(ed->fields.server->angles);
1982 ed->fields.server->nextthink = -1;
1983 ed->fields.server->solid = 0;
1986 void SV_VM_CB_CountEdicts(void)
1990 int active, models, solid, step;
1992 active = models = solid = step = 0;
1993 for (i=0 ; i<prog->num_edicts ; i++)
1995 ent = PRVM_EDICT_NUM(i);
1996 if (ent->priv.server->free)
1999 if (ent->fields.server->solid)
2001 if (ent->fields.server->model)
2003 if (ent->fields.server->movetype == MOVETYPE_STEP)
2007 Con_Printf("num_edicts:%3i\n", prog->num_edicts);
2008 Con_Printf("active :%3i\n", active);
2009 Con_Printf("view :%3i\n", models);
2010 Con_Printf("touch :%3i\n", solid);
2011 Con_Printf("step :%3i\n", step);
2014 qboolean SV_VM_CB_LoadEdict(prvm_edict_t *ent)
2016 // remove things from different skill levels or deathmatch
2017 if (gamemode != GAME_TRANSFUSION) //Transfusion does this in QC
2019 if (deathmatch.integer)
2021 if (((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
2026 else if ((current_skill <= 0 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_EASY ))
2027 || (current_skill == 1 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_MEDIUM))
2028 || (current_skill >= 2 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_HARD )))
2036 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)"};
2037 cvar_t nomonsters = {0, "nomonsters", "0", "unused cvar in quake, can be used by mods"};
2038 cvar_t gamecfg = {0, "gamecfg", "0", "unused cvar in quake, can be used by mods"};
2039 cvar_t scratch1 = {0, "scratch1", "0", "unused cvar in quake, can be used by mods"};
2040 cvar_t scratch2 = {0,"scratch2", "0", "unused cvar in quake, can be used by mods"};
2041 cvar_t scratch3 = {0, "scratch3", "0", "unused cvar in quake, can be used by mods"};
2042 cvar_t scratch4 = {0, "scratch4", "0", "unused cvar in quake, can be used by mods"};
2043 cvar_t savedgamecfg = {CVAR_SAVE, "savedgamecfg", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2044 cvar_t saved1 = {CVAR_SAVE, "saved1", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2045 cvar_t saved2 = {CVAR_SAVE, "saved2", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2046 cvar_t saved3 = {CVAR_SAVE, "saved3", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2047 cvar_t saved4 = {CVAR_SAVE, "saved4", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2048 cvar_t nehx00 = {0, "nehx00", "0", "nehahra data storage cvar (used in singleplayer)"};
2049 cvar_t nehx01 = {0, "nehx01", "0", "nehahra data storage cvar (used in singleplayer)"};
2050 cvar_t nehx02 = {0, "nehx02", "0", "nehahra data storage cvar (used in singleplayer)"};
2051 cvar_t nehx03 = {0, "nehx03", "0", "nehahra data storage cvar (used in singleplayer)"};
2052 cvar_t nehx04 = {0, "nehx04", "0", "nehahra data storage cvar (used in singleplayer)"};
2053 cvar_t nehx05 = {0, "nehx05", "0", "nehahra data storage cvar (used in singleplayer)"};
2054 cvar_t nehx06 = {0, "nehx06", "0", "nehahra data storage cvar (used in singleplayer)"};
2055 cvar_t nehx07 = {0, "nehx07", "0", "nehahra data storage cvar (used in singleplayer)"};
2056 cvar_t nehx08 = {0, "nehx08", "0", "nehahra data storage cvar (used in singleplayer)"};
2057 cvar_t nehx09 = {0, "nehx09", "0", "nehahra data storage cvar (used in singleplayer)"};
2058 cvar_t nehx10 = {0, "nehx10", "0", "nehahra data storage cvar (used in singleplayer)"};
2059 cvar_t nehx11 = {0, "nehx11", "0", "nehahra data storage cvar (used in singleplayer)"};
2060 cvar_t nehx12 = {0, "nehx12", "0", "nehahra data storage cvar (used in singleplayer)"};
2061 cvar_t nehx13 = {0, "nehx13", "0", "nehahra data storage cvar (used in singleplayer)"};
2062 cvar_t nehx14 = {0, "nehx14", "0", "nehahra data storage cvar (used in singleplayer)"};
2063 cvar_t nehx15 = {0, "nehx15", "0", "nehahra data storage cvar (used in singleplayer)"};
2064 cvar_t nehx16 = {0, "nehx16", "0", "nehahra data storage cvar (used in singleplayer)"};
2065 cvar_t nehx17 = {0, "nehx17", "0", "nehahra data storage cvar (used in singleplayer)"};
2066 cvar_t nehx18 = {0, "nehx18", "0", "nehahra data storage cvar (used in singleplayer)"};
2067 cvar_t nehx19 = {0, "nehx19", "0", "nehahra data storage cvar (used in singleplayer)"};
2068 cvar_t cutscene = {0, "cutscene", "1", "enables cutscenes in nehahra, can be used by other mods"};
2070 void SV_VM_Init(void)
2072 Cvar_RegisterVariable (&pr_checkextension);
2073 Cvar_RegisterVariable (&nomonsters);
2074 Cvar_RegisterVariable (&gamecfg);
2075 Cvar_RegisterVariable (&scratch1);
2076 Cvar_RegisterVariable (&scratch2);
2077 Cvar_RegisterVariable (&scratch3);
2078 Cvar_RegisterVariable (&scratch4);
2079 Cvar_RegisterVariable (&savedgamecfg);
2080 Cvar_RegisterVariable (&saved1);
2081 Cvar_RegisterVariable (&saved2);
2082 Cvar_RegisterVariable (&saved3);
2083 Cvar_RegisterVariable (&saved4);
2084 // LordHavoc: Nehahra uses these to pass data around cutscene demos
2085 if (gamemode == GAME_NEHAHRA)
2087 Cvar_RegisterVariable (&nehx00);
2088 Cvar_RegisterVariable (&nehx01);
2089 Cvar_RegisterVariable (&nehx02);
2090 Cvar_RegisterVariable (&nehx03);
2091 Cvar_RegisterVariable (&nehx04);
2092 Cvar_RegisterVariable (&nehx05);
2093 Cvar_RegisterVariable (&nehx06);
2094 Cvar_RegisterVariable (&nehx07);
2095 Cvar_RegisterVariable (&nehx08);
2096 Cvar_RegisterVariable (&nehx09);
2097 Cvar_RegisterVariable (&nehx10);
2098 Cvar_RegisterVariable (&nehx11);
2099 Cvar_RegisterVariable (&nehx12);
2100 Cvar_RegisterVariable (&nehx13);
2101 Cvar_RegisterVariable (&nehx14);
2102 Cvar_RegisterVariable (&nehx15);
2103 Cvar_RegisterVariable (&nehx16);
2104 Cvar_RegisterVariable (&nehx17);
2105 Cvar_RegisterVariable (&nehx18);
2106 Cvar_RegisterVariable (&nehx19);
2108 Cvar_RegisterVariable (&cutscene); // for Nehahra but useful to other mods as well
2111 // LordHavoc: in an effort to eliminate time wasted on GetEdictFieldValue... these are defined as externs in progs.h
2128 int eval_buttonchat;
2130 int eval_glow_trail;
2131 int eval_glow_color;
2135 int eval_renderamt; // HalfLife support
2136 int eval_rendermode; // HalfLife support
2137 int eval_fullbright;
2138 int eval_ammo_shells1;
2139 int eval_ammo_nails1;
2140 int eval_ammo_lava_nails;
2141 int eval_ammo_rockets1;
2142 int eval_ammo_multi_rockets;
2143 int eval_ammo_cells1;
2144 int eval_ammo_plasma;
2145 int eval_idealpitch;
2146 int eval_pitch_speed;
2147 int eval_viewmodelforclient;
2148 int eval_nodrawtoclient;
2149 int eval_exteriormodeltoclient;
2150 int eval_drawonlytoclient;
2154 int eval_punchvector;
2156 int eval_clientcolors;
2157 int eval_tag_entity;
2163 int eval_cursor_active;
2164 int eval_cursor_screen;
2165 int eval_cursor_trace_start;
2166 int eval_cursor_trace_endpos;
2167 int eval_cursor_trace_ent;
2169 int eval_playermodel;
2170 int eval_playerskin;
2171 int eval_SendEntity;
2173 int eval_customizeentityforclient;
2174 int eval_dphitcontentsmask;
2176 int gval_trace_dpstartcontents;
2177 int gval_trace_dphitcontents;
2178 int gval_trace_dphitq3surfaceflags;
2179 int gval_trace_dphittexturename;
2181 mfunction_t *SV_PlayerPhysicsQC;
2182 mfunction_t *EndFrameQC;
2183 //KrimZon - SERVER COMMANDS IN QUAKEC
2184 mfunction_t *SV_ParseClientCommandQC;
2186 ddef_t *PRVM_ED_FindGlobal(const char *name);
2188 void SV_VM_FindEdictFieldOffsets(void)
2190 eval_gravity = PRVM_ED_FindFieldOffset("gravity");
2191 eval_button3 = PRVM_ED_FindFieldOffset("button3");
2192 eval_button4 = PRVM_ED_FindFieldOffset("button4");
2193 eval_button5 = PRVM_ED_FindFieldOffset("button5");
2194 eval_button6 = PRVM_ED_FindFieldOffset("button6");
2195 eval_button7 = PRVM_ED_FindFieldOffset("button7");
2196 eval_button8 = PRVM_ED_FindFieldOffset("button8");
2197 eval_button9 = PRVM_ED_FindFieldOffset("button9");
2198 eval_button10 = PRVM_ED_FindFieldOffset("button10");
2199 eval_button11 = PRVM_ED_FindFieldOffset("button11");
2200 eval_button12 = PRVM_ED_FindFieldOffset("button12");
2201 eval_button13 = PRVM_ED_FindFieldOffset("button13");
2202 eval_button14 = PRVM_ED_FindFieldOffset("button14");
2203 eval_button15 = PRVM_ED_FindFieldOffset("button15");
2204 eval_button16 = PRVM_ED_FindFieldOffset("button16");
2205 eval_buttonuse = PRVM_ED_FindFieldOffset("buttonuse");
2206 eval_buttonchat = PRVM_ED_FindFieldOffset("buttonchat");
2207 eval_glow_size = PRVM_ED_FindFieldOffset("glow_size");
2208 eval_glow_trail = PRVM_ED_FindFieldOffset("glow_trail");
2209 eval_glow_color = PRVM_ED_FindFieldOffset("glow_color");
2210 eval_items2 = PRVM_ED_FindFieldOffset("items2");
2211 eval_scale = PRVM_ED_FindFieldOffset("scale");
2212 eval_alpha = PRVM_ED_FindFieldOffset("alpha");
2213 eval_renderamt = PRVM_ED_FindFieldOffset("renderamt"); // HalfLife support
2214 eval_rendermode = PRVM_ED_FindFieldOffset("rendermode"); // HalfLife support
2215 eval_fullbright = PRVM_ED_FindFieldOffset("fullbright");
2216 eval_ammo_shells1 = PRVM_ED_FindFieldOffset("ammo_shells1");
2217 eval_ammo_nails1 = PRVM_ED_FindFieldOffset("ammo_nails1");
2218 eval_ammo_lava_nails = PRVM_ED_FindFieldOffset("ammo_lava_nails");
2219 eval_ammo_rockets1 = PRVM_ED_FindFieldOffset("ammo_rockets1");
2220 eval_ammo_multi_rockets = PRVM_ED_FindFieldOffset("ammo_multi_rockets");
2221 eval_ammo_cells1 = PRVM_ED_FindFieldOffset("ammo_cells1");
2222 eval_ammo_plasma = PRVM_ED_FindFieldOffset("ammo_plasma");
2223 eval_idealpitch = PRVM_ED_FindFieldOffset("idealpitch");
2224 eval_pitch_speed = PRVM_ED_FindFieldOffset("pitch_speed");
2225 eval_viewmodelforclient = PRVM_ED_FindFieldOffset("viewmodelforclient");
2226 eval_nodrawtoclient = PRVM_ED_FindFieldOffset("nodrawtoclient");
2227 eval_exteriormodeltoclient = PRVM_ED_FindFieldOffset("exteriormodeltoclient");
2228 eval_drawonlytoclient = PRVM_ED_FindFieldOffset("drawonlytoclient");
2229 eval_ping = PRVM_ED_FindFieldOffset("ping");
2230 eval_movement = PRVM_ED_FindFieldOffset("movement");
2231 eval_pmodel = PRVM_ED_FindFieldOffset("pmodel");
2232 eval_punchvector = PRVM_ED_FindFieldOffset("punchvector");
2233 eval_viewzoom = PRVM_ED_FindFieldOffset("viewzoom");
2234 eval_clientcolors = PRVM_ED_FindFieldOffset("clientcolors");
2235 eval_tag_entity = PRVM_ED_FindFieldOffset("tag_entity");
2236 eval_tag_index = PRVM_ED_FindFieldOffset("tag_index");
2237 eval_light_lev = PRVM_ED_FindFieldOffset("light_lev");
2238 eval_color = PRVM_ED_FindFieldOffset("color");
2239 eval_style = PRVM_ED_FindFieldOffset("style");
2240 eval_pflags = PRVM_ED_FindFieldOffset("pflags");
2241 eval_cursor_active = PRVM_ED_FindFieldOffset("cursor_active");
2242 eval_cursor_screen = PRVM_ED_FindFieldOffset("cursor_screen");
2243 eval_cursor_trace_start = PRVM_ED_FindFieldOffset("cursor_trace_start");
2244 eval_cursor_trace_endpos = PRVM_ED_FindFieldOffset("cursor_trace_endpos");
2245 eval_cursor_trace_ent = PRVM_ED_FindFieldOffset("cursor_trace_ent");
2246 eval_colormod = PRVM_ED_FindFieldOffset("colormod");
2247 eval_playermodel = PRVM_ED_FindFieldOffset("playermodel");
2248 eval_playerskin = PRVM_ED_FindFieldOffset("playerskin");
2249 eval_SendEntity = PRVM_ED_FindFieldOffset("SendEntity");
2250 eval_Version = PRVM_ED_FindFieldOffset("Version");
2251 eval_customizeentityforclient = PRVM_ED_FindFieldOffset("customizeentityforclient");
2252 eval_dphitcontentsmask = PRVM_ED_FindFieldOffset("dphitcontentsmask");
2254 // LordHavoc: allowing QuakeC to override the player movement code
2255 SV_PlayerPhysicsQC = PRVM_ED_FindFunction ("SV_PlayerPhysics");
2256 // LordHavoc: support for endframe
2257 EndFrameQC = PRVM_ED_FindFunction ("EndFrame");
2258 //KrimZon - SERVER COMMANDS IN QUAKEC
2259 SV_ParseClientCommandQC = PRVM_ED_FindFunction ("SV_ParseClientCommand");
2261 //[515]: init stufftext string (it is sent before svc_serverinfo)
2262 if(PRVM_ED_FindGlobal("SV_InitCmd") && PRVM_ED_FindGlobal("SV_InitCmd")->type & ev_string)
2263 SV_InitCmd = PRVM_G_STRING(PRVM_ED_FindGlobal("SV_InitCmd")->ofs);
2267 gval_trace_dpstartcontents = PRVM_ED_FindGlobalOffset("trace_dpstartcontents");
2268 gval_trace_dphitcontents = PRVM_ED_FindGlobalOffset("trace_dphitcontents");
2269 gval_trace_dphitq3surfaceflags = PRVM_ED_FindGlobalOffset("trace_dphitq3surfaceflags");
2270 gval_trace_dphittexturename = PRVM_ED_FindGlobalOffset("trace_dphittexturename");
2273 #define REQFIELDS (sizeof(reqfields) / sizeof(prvm_required_field_t))
2275 prvm_required_field_t reqfields[] =
2277 {ev_entity, "cursor_trace_ent"},
2278 {ev_entity, "drawonlytoclient"},
2279 {ev_entity, "exteriormodeltoclient"},
2280 {ev_entity, "nodrawtoclient"},
2281 {ev_entity, "tag_entity"},
2282 {ev_entity, "viewmodelforclient"},
2283 {ev_float, "alpha"},
2284 {ev_float, "ammo_cells1"},
2285 {ev_float, "ammo_lava_nails"},
2286 {ev_float, "ammo_multi_rockets"},
2287 {ev_float, "ammo_nails1"},
2288 {ev_float, "ammo_plasma"},
2289 {ev_float, "ammo_rockets1"},
2290 {ev_float, "ammo_shells1"},
2291 {ev_float, "button3"},
2292 {ev_float, "button4"},
2293 {ev_float, "button5"},
2294 {ev_float, "button6"},
2295 {ev_float, "button7"},
2296 {ev_float, "button8"},
2297 {ev_float, "button9"},
2298 {ev_float, "button10"},
2299 {ev_float, "button11"},
2300 {ev_float, "button12"},
2301 {ev_float, "button13"},
2302 {ev_float, "button14"},
2303 {ev_float, "button15"},
2304 {ev_float, "button16"},
2305 {ev_float, "buttonchat"},
2306 {ev_float, "buttonuse"},
2307 {ev_float, "clientcolors"},
2308 {ev_float, "cursor_active"},
2309 {ev_float, "fullbright"},
2310 {ev_float, "glow_color"},
2311 {ev_float, "glow_size"},
2312 {ev_float, "glow_trail"},
2313 {ev_float, "gravity"},
2314 {ev_float, "idealpitch"},
2315 {ev_float, "items2"},
2316 {ev_float, "light_lev"},
2317 {ev_float, "pflags"},
2319 {ev_float, "pitch_speed"},
2320 {ev_float, "pmodel"},
2321 {ev_float, "renderamt"}, // HalfLife support
2322 {ev_float, "rendermode"}, // HalfLife support
2323 {ev_float, "scale"},
2324 {ev_float, "style"},
2325 {ev_float, "tag_index"},
2326 {ev_float, "Version"},
2327 {ev_float, "viewzoom"},
2328 {ev_vector, "color"},
2329 {ev_vector, "colormod"},
2330 {ev_vector, "cursor_screen"},
2331 {ev_vector, "cursor_trace_endpos"},
2332 {ev_vector, "cursor_trace_start"},
2333 {ev_vector, "movement"},
2334 {ev_vector, "punchvector"},
2335 {ev_string, "playermodel"},
2336 {ev_string, "playerskin"},
2337 {ev_function, "SendEntity"},
2338 {ev_function, "customizeentityforclient"},
2341 void SV_VM_Setup(void)
2344 PRVM_InitProg( PRVM_SERVERPROG );
2346 // allocate the mempools
2347 prog->progs_mempool = Mem_AllocPool("Server Progs", 0, NULL);
2348 prog->builtins = vm_sv_builtins;
2349 prog->numbuiltins = vm_sv_numbuiltins;
2350 prog->headercrc = PROGHEADER_CRC;
2351 prog->max_edicts = 512;
2352 prog->limit_edicts = MAX_EDICTS;
2353 prog->reserved_edicts = svs.maxclients;
2354 prog->edictprivate_size = sizeof(edict_engineprivate_t);
2355 prog->name = "server";
2356 prog->extensionstring = vm_sv_extensions;
2357 prog->loadintoworld = true;
2359 prog->begin_increase_edicts = SV_VM_CB_BeginIncreaseEdicts;
2360 prog->end_increase_edicts = SV_VM_CB_EndIncreaseEdicts;
2361 prog->init_edict = SV_VM_CB_InitEdict;
2362 prog->free_edict = SV_VM_CB_FreeEdict;
2363 prog->count_edicts = SV_VM_CB_CountEdicts;
2364 prog->load_edict = SV_VM_CB_LoadEdict;
2365 prog->init_cmd = VM_SV_Cmd_Init;
2366 prog->reset_cmd = VM_SV_Cmd_Reset;
2367 prog->error_cmd = Host_Error;
2369 // TODO: add a requiredfuncs list (ask LH if this is necessary at all)
2370 PRVM_LoadProgs( sv_progs.string, 0, NULL, REQFIELDS, reqfields );
2371 SV_VM_FindEdictFieldOffsets();
2373 VM_AutoSentStats_Clear();//[515]: csqc
2374 EntityFrameCSQC_ClearVersions();//[515]: csqc
2379 void SV_VM_Begin(void)
2382 PRVM_SetProg( PRVM_SERVERPROG );
2384 *prog->time = (float) sv.time;
2387 void SV_VM_End(void)