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"};
54 cvar_t sv_gameplayfix_upwardvelocityclearsongroundflag = {0, "sv_gameplayfix_upwardvelocityclearsongroundflag", "1", "prevents monsters, items, and most other objects from being stuck to the floor when pushed around by damage, and other situations in mods"};
56 cvar_t sv_progs = {0, "sv_progs", "progs.dat", "selects which quakec progs.dat file to run" };
58 // TODO: move these cvars here
59 extern cvar_t sv_clmovement_enable;
60 extern cvar_t sv_clmovement_minping;
61 extern cvar_t sv_clmovement_minping_disabletime;
62 extern cvar_t sv_clmovement_waitforinput;
67 mempool_t *sv_mempool = NULL;
69 //============================================================================
71 extern void SV_Phys_Init (void);
72 extern void SV_World_Init (void);
73 static void SV_SaveEntFile_f(void);
82 Cmd_AddCommand("sv_saveentfile", SV_SaveEntFile_f, "save map entities to .ent file (to allow external editing)");
83 Cvar_RegisterVariable (&sv_maxvelocity);
84 Cvar_RegisterVariable (&sv_gravity);
85 Cvar_RegisterVariable (&sv_friction);
86 Cvar_RegisterVariable (&sv_waterfriction);
87 Cvar_RegisterVariable (&sv_edgefriction);
88 Cvar_RegisterVariable (&sv_stopspeed);
89 Cvar_RegisterVariable (&sv_maxspeed);
90 Cvar_RegisterVariable (&sv_maxairspeed);
91 Cvar_RegisterVariable (&sv_accelerate);
92 Cvar_RegisterVariable (&sv_airaccelerate);
93 Cvar_RegisterVariable (&sv_wateraccelerate);
94 Cvar_RegisterVariable (&sv_clmovement_enable);
95 Cvar_RegisterVariable (&sv_clmovement_minping);
96 Cvar_RegisterVariable (&sv_clmovement_minping_disabletime);
97 Cvar_RegisterVariable (&sv_clmovement_waitforinput);
98 Cvar_RegisterVariable (&sv_idealpitchscale);
99 Cvar_RegisterVariable (&sv_aim);
100 Cvar_RegisterVariable (&sv_nostep);
101 Cvar_RegisterVariable (&sv_cullentities_pvs);
102 Cvar_RegisterVariable (&sv_cullentities_trace);
103 Cvar_RegisterVariable (&sv_cullentities_stats);
104 Cvar_RegisterVariable (&sv_entpatch);
105 Cvar_RegisterVariable (&sv_gameplayfix_grenadebouncedownslopes);
106 Cvar_RegisterVariable (&sv_gameplayfix_noairborncorpse);
107 Cvar_RegisterVariable (&sv_gameplayfix_stepdown);
108 Cvar_RegisterVariable (&sv_gameplayfix_stepwhilejumping);
109 Cvar_RegisterVariable (&sv_gameplayfix_swiminbmodels);
110 Cvar_RegisterVariable (&sv_gameplayfix_setmodelrealbox);
111 Cvar_RegisterVariable (&sv_gameplayfix_blowupfallenzombies);
112 Cvar_RegisterVariable (&sv_gameplayfix_findradiusdistancetobox);
113 Cvar_RegisterVariable (&sv_gameplayfix_qwplayerphysics);
114 Cvar_RegisterVariable (&sv_gameplayfix_upwardvelocityclearsongroundflag);
115 Cvar_RegisterVariable (&sv_protocolname);
116 Cvar_RegisterVariable (&sv_ratelimitlocalplayer);
117 Cvar_RegisterVariable (&sv_maxrate);
118 Cvar_RegisterVariable (&sv_progs);
124 sv_mempool = Mem_AllocPool("server", 0, NULL);
127 static void SV_SaveEntFile_f(void)
129 char basename[MAX_QPATH];
130 if (!sv.active || !sv.worldmodel)
132 Con_Print("Not running a server\n");
135 FS_StripExtension(sv.worldmodel->name, basename, sizeof(basename));
136 FS_WriteFile(va("%s.ent", basename), sv.worldmodel->brush.entities, (fs_offset_t)strlen(sv.worldmodel->brush.entities));
141 =============================================================================
145 =============================================================================
152 Make sure the event gets sent to all clients
155 void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count)
159 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-18)
161 MSG_WriteByte (&sv.datagram, svc_particle);
162 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
163 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
164 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
165 for (i=0 ; i<3 ; i++)
166 MSG_WriteChar (&sv.datagram, (int)bound(-128, dir[i]*16, 127));
167 MSG_WriteByte (&sv.datagram, count);
168 MSG_WriteByte (&sv.datagram, color);
175 Make sure the event gets sent to all clients
178 void SV_StartEffect (vec3_t org, int modelindex, int startframe, int framecount, int framerate)
180 if (modelindex >= 256 || startframe >= 256)
182 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-19)
184 MSG_WriteByte (&sv.datagram, svc_effect2);
185 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
186 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
187 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
188 MSG_WriteShort (&sv.datagram, modelindex);
189 MSG_WriteShort (&sv.datagram, startframe);
190 MSG_WriteByte (&sv.datagram, framecount);
191 MSG_WriteByte (&sv.datagram, framerate);
195 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-17)
197 MSG_WriteByte (&sv.datagram, svc_effect);
198 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
199 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
200 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
201 MSG_WriteByte (&sv.datagram, modelindex);
202 MSG_WriteByte (&sv.datagram, startframe);
203 MSG_WriteByte (&sv.datagram, framecount);
204 MSG_WriteByte (&sv.datagram, framerate);
212 Each entity can have eight independant sound sources, like voice,
215 Channel 0 is an auto-allocate channel, the others override anything
216 already running on that entity/channel pair.
218 An attenuation of 0 will play full volume everywhere in the level.
219 Larger attenuations will drop off. (max 4 attenuation)
223 void SV_StartSound (prvm_edict_t *entity, int channel, const char *sample, int volume, float attenuation)
225 int sound_num, field_mask, i, ent;
227 if (volume < 0 || volume > 255)
229 Con_Printf ("SV_StartSound: volume = %i\n", volume);
233 if (attenuation < 0 || attenuation > 4)
235 Con_Printf ("SV_StartSound: attenuation = %f\n", attenuation);
239 if (channel < 0 || channel > 7)
241 Con_Printf ("SV_StartSound: channel = %i\n", channel);
245 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-21)
248 // find precache number for sound
249 sound_num = SV_SoundIndex(sample, 1);
253 ent = PRVM_NUM_FOR_EDICT(entity);
256 if (volume != DEFAULT_SOUND_PACKET_VOLUME)
257 field_mask |= SND_VOLUME;
258 if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
259 field_mask |= SND_ATTENUATION;
261 field_mask |= SND_LARGEENTITY;
262 if (sound_num >= 256 || channel >= 8)
263 field_mask |= SND_LARGESOUND;
265 // directed messages go only to the entity they are targeted on
266 MSG_WriteByte (&sv.datagram, svc_sound);
267 MSG_WriteByte (&sv.datagram, field_mask);
268 if (field_mask & SND_VOLUME)
269 MSG_WriteByte (&sv.datagram, volume);
270 if (field_mask & SND_ATTENUATION)
271 MSG_WriteByte (&sv.datagram, (int)(attenuation*64));
272 if (field_mask & SND_LARGEENTITY)
274 MSG_WriteShort (&sv.datagram, ent);
275 MSG_WriteByte (&sv.datagram, channel);
278 MSG_WriteShort (&sv.datagram, (ent<<3) | channel);
279 if (field_mask & SND_LARGESOUND)
280 MSG_WriteShort (&sv.datagram, sound_num);
282 MSG_WriteByte (&sv.datagram, sound_num);
283 for (i = 0;i < 3;i++)
284 MSG_WriteCoord (&sv.datagram, entity->fields.server->origin[i]+0.5*(entity->fields.server->mins[i]+entity->fields.server->maxs[i]), sv.protocol);
288 ==============================================================================
292 ==============================================================================
295 static const char *SV_InitCmd; //[515]: svprogs able to send cmd to client on connect
296 extern qboolean csqc_loaded;
301 Sends the first message from the server to a connected client.
302 This will be sent on the initial connection and upon each server load.
305 void SV_SendServerinfo (client_t *client)
310 // we know that this client has a netconnection and thus is not a bot
312 // edicts get reallocated on level changes, so we need to update it here
313 client->edict = PRVM_EDICT_NUM((client - svs.clients) + 1);
315 // clear cached stuff that depends on the level
316 client->weaponmodel[0] = 0;
317 client->weaponmodelindex = 0;
319 // LordHavoc: clear entityframe tracking
320 client->latestframenum = 0;
322 if (client->entitydatabase)
323 EntityFrame_FreeDatabase(client->entitydatabase);
324 if (client->entitydatabase4)
325 EntityFrame4_FreeDatabase(client->entitydatabase4);
326 if (client->entitydatabase5)
327 EntityFrame5_FreeDatabase(client->entitydatabase5);
329 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
331 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3)
332 client->entitydatabase = EntityFrame_AllocDatabase(sv_mempool);
333 else if (sv.protocol == PROTOCOL_DARKPLACES4)
334 client->entitydatabase4 = EntityFrame4_AllocDatabase(sv_mempool);
336 client->entitydatabase5 = EntityFrame5_AllocDatabase(sv_mempool);
339 SZ_Clear (&client->netconnection->message);
340 MSG_WriteByte (&client->netconnection->message, svc_print);
341 dpsnprintf (message, sizeof (message), "\nServer: %s build %s (progs %i crc)", gamename, buildstring, prog->filecrc);
342 MSG_WriteString (&client->netconnection->message,message);
344 // FIXME: LordHavoc: this does not work on dedicated servers, needs fixing.
345 //[515]: init csprogs according to version of svprogs, check the crc, etc.
346 if(csqc_loaded && (cls.state == ca_dedicated || PRVM_NUM_FOR_EDICT(client->edict) != 1))
348 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
350 MSG_WriteString (&client->netconnection->message, va("csqc_progcrc %i;%s\n", csqc_progcrc.integer, SV_InitCmd));
352 MSG_WriteString (&client->netconnection->message, va("csqc_progcrc %i\n", csqc_progcrc.integer));
355 MSG_WriteByte (&client->netconnection->message, svc_serverinfo);
356 MSG_WriteLong (&client->netconnection->message, Protocol_NumberForEnum(sv.protocol));
357 MSG_WriteByte (&client->netconnection->message, svs.maxclients);
359 if (!coop.integer && deathmatch.integer)
360 MSG_WriteByte (&client->netconnection->message, GAME_DEATHMATCH);
362 MSG_WriteByte (&client->netconnection->message, GAME_COOP);
364 MSG_WriteString (&client->netconnection->message,PRVM_GetString(prog->edicts->fields.server->message));
366 for (i = 1;i < MAX_MODELS && sv.model_precache[i][0];i++)
367 MSG_WriteString (&client->netconnection->message, sv.model_precache[i]);
368 MSG_WriteByte (&client->netconnection->message, 0);
370 for (i = 1;i < MAX_SOUNDS && sv.sound_precache[i][0];i++)
371 MSG_WriteString (&client->netconnection->message, sv.sound_precache[i]);
372 MSG_WriteByte (&client->netconnection->message, 0);
375 MSG_WriteByte (&client->netconnection->message, svc_cdtrack);
376 MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
377 MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
380 MSG_WriteByte (&client->netconnection->message, svc_setview);
381 MSG_WriteShort (&client->netconnection->message, PRVM_NUM_FOR_EDICT(client->edict));
383 MSG_WriteByte (&client->netconnection->message, svc_signonnum);
384 MSG_WriteByte (&client->netconnection->message, 1);
386 client->spawned = false; // need prespawn, spawn, etc
393 Initializes a client_t for a new net connection. This will only be called
394 once for a player each game, not once for each level change.
397 void SV_ConnectClient (int clientnum, netconn_t *netconnection)
401 float spawn_parms[NUM_SPAWN_PARMS];
403 client = svs.clients + clientnum;
405 if(netconnection)//[515]: bots don't play with csqc =)
406 EntityFrameCSQC_InitClientVersions(clientnum, false);
408 // set up the client_t
410 memcpy (spawn_parms, client->spawn_parms, sizeof(spawn_parms));
411 memset (client, 0, sizeof(*client));
412 client->active = true;
413 client->netconnection = netconnection;
415 Con_DPrintf("Client %s connected\n", client->netconnection ? client->netconnection->address : "botclient");
417 strlcpy(client->name, "unconnected", sizeof(client->name));
418 strlcpy(client->old_name, "unconnected", sizeof(client->old_name));
419 client->spawned = false;
420 client->edict = PRVM_EDICT_NUM(clientnum+1);
421 if (client->netconnection)
422 client->netconnection->message.allowoverflow = true; // we can catch it
423 // updated by receiving "rate" command from client
424 client->rate = NET_MINRATE;
425 // no limits for local player
426 if (client->netconnection && LHNETADDRESS_GetAddressType(&client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP)
427 client->rate = 1000000000;
428 client->connecttime = realtime;
431 memcpy (client->spawn_parms, spawn_parms, sizeof(spawn_parms));
434 // call the progs to get default spawn parms for the new client
435 // set self to world to intentionally cause errors with broken SetNewParms code in some mods
436 prog->globals.server->self = 0;
437 PRVM_ExecuteProgram (prog->globals.server->SetNewParms, "QC function SetNewParms is missing");
438 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
439 client->spawn_parms[i] = (&prog->globals.server->parm1)[i];
441 // set up the entity for this client (including .colormap, .team, etc)
442 PRVM_ED_ClearEdict(client->edict);
445 // don't call SendServerinfo for a fresh botclient because its fields have
446 // not been set up by the qc yet
447 if (client->netconnection)
448 SV_SendServerinfo (client);
450 client->spawned = true;
455 ===============================================================================
459 ===============================================================================
468 void SV_ClearDatagram (void)
470 SZ_Clear (&sv.datagram);
474 =============================================================================
476 The PVS must include a small area around the client to allow head bobbing
477 or other small motion on the client side. Otherwise, a bob might cause an
478 entity that should be visible to not show up, especially when the bob
481 =============================================================================
484 int sv_writeentitiestoclient_pvsbytes;
485 unsigned char sv_writeentitiestoclient_pvs[MAX_MAP_LEAFS/8];
487 static int numsendentities;
488 static entity_state_t sendentities[MAX_EDICTS];
489 static entity_state_t *sendentitiesindex[MAX_EDICTS];
491 qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *cs, int e)
494 unsigned int modelindex, effects, flags, glowsize, lightstyle, lightpflags, light[4], specialvisibilityradius;
495 unsigned int customizeentityforclient;
497 vec3_t cullmins, cullmaxs;
501 // EF_NODRAW prevents sending for any reason except for your own
502 // client, so we must keep all clients in this superset
503 effects = (unsigned)ent->fields.server->effects;
505 // we can omit invisible entities with no effects that are not clients
506 // LordHavoc: this could kill tags attached to an invisible entity, I
507 // just hope we never have to support that case
508 i = (int)ent->fields.server->modelindex;
509 modelindex = (i >= 1 && i < MAX_MODELS && *PRVM_GetString(ent->fields.server->model)) ? i : 0;
512 i = (int)(PRVM_GETEDICTFIELDVALUE(ent, eval_glow_size)->_float * 0.25f);
513 glowsize = (unsigned char)bound(0, i, 255);
514 if (PRVM_GETEDICTFIELDVALUE(ent, eval_glow_trail)->_float)
515 flags |= RENDER_GLOWTRAIL;
517 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[0]*256;
518 light[0] = (unsigned short)bound(0, f, 65535);
519 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[1]*256;
520 light[1] = (unsigned short)bound(0, f, 65535);
521 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[2]*256;
522 light[2] = (unsigned short)bound(0, f, 65535);
523 f = PRVM_GETEDICTFIELDVALUE(ent, eval_light_lev)->_float;
524 light[3] = (unsigned short)bound(0, f, 65535);
525 lightstyle = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_style)->_float;
526 lightpflags = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_pflags)->_float;
528 if (gamemode == GAME_TENEBRAE)
530 // tenebrae's EF_FULLDYNAMIC conflicts with Q2's EF_NODRAW
534 lightpflags |= PFLAGS_FULLDYNAMIC;
536 // tenebrae's EF_GREEN conflicts with DP's EF_ADDITIVE
540 light[0] = (int)(0.2*256);
541 light[1] = (int)(1.0*256);
542 light[2] = (int)(0.2*256);
544 lightpflags |= PFLAGS_FULLDYNAMIC;
548 specialvisibilityradius = 0;
549 if (lightpflags & PFLAGS_FULLDYNAMIC)
550 specialvisibilityradius = max(specialvisibilityradius, light[3]);
552 specialvisibilityradius = max(specialvisibilityradius, glowsize * 4);
553 if (flags & RENDER_GLOWTRAIL)
554 specialvisibilityradius = max(specialvisibilityradius, 100);
555 if (effects & (EF_BRIGHTFIELD | EF_MUZZLEFLASH | EF_BRIGHTLIGHT | EF_DIMLIGHT | EF_RED | EF_BLUE | EF_FLAME | EF_STARDUST))
557 if (effects & EF_BRIGHTFIELD)
558 specialvisibilityradius = max(specialvisibilityradius, 80);
559 if (effects & EF_MUZZLEFLASH)
560 specialvisibilityradius = max(specialvisibilityradius, 100);
561 if (effects & EF_BRIGHTLIGHT)
562 specialvisibilityradius = max(specialvisibilityradius, 400);
563 if (effects & EF_DIMLIGHT)
564 specialvisibilityradius = max(specialvisibilityradius, 200);
565 if (effects & EF_RED)
566 specialvisibilityradius = max(specialvisibilityradius, 200);
567 if (effects & EF_BLUE)
568 specialvisibilityradius = max(specialvisibilityradius, 200);
569 if (effects & EF_FLAME)
570 specialvisibilityradius = max(specialvisibilityradius, 250);
571 if (effects & EF_STARDUST)
572 specialvisibilityradius = max(specialvisibilityradius, 100);
575 // early culling checks
576 // (final culling is done by SV_MarkWriteEntityStateToClient)
577 customizeentityforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_customizeentityforclient)->function;
578 if (!customizeentityforclient)
580 if (e > svs.maxclients && (!modelindex && !specialvisibilityradius))
582 // this 2 billion unit check is actually to detect NAN origins
583 // (we really don't want to send those)
584 if (VectorLength2(ent->fields.server->origin) > 2000000000.0*2000000000.0)
592 VectorCopy(ent->fields.server->origin, cs->origin);
593 VectorCopy(ent->fields.server->angles, cs->angles);
595 cs->effects = effects;
596 cs->colormap = (unsigned)ent->fields.server->colormap;
597 cs->modelindex = modelindex;
598 cs->skin = (unsigned)ent->fields.server->skin;
599 cs->frame = (unsigned)ent->fields.server->frame;
600 cs->viewmodelforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)->edict;
601 cs->exteriormodelforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_exteriormodeltoclient)->edict;
602 cs->nodrawtoclient = PRVM_GETEDICTFIELDVALUE(ent, eval_nodrawtoclient)->edict;
603 cs->drawonlytoclient = PRVM_GETEDICTFIELDVALUE(ent, eval_drawonlytoclient)->edict;
604 cs->customizeentityforclient = customizeentityforclient;
605 cs->tagentity = PRVM_GETEDICTFIELDVALUE(ent, eval_tag_entity)->edict;
606 cs->tagindex = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_tag_index)->_float;
607 cs->glowsize = glowsize;
609 // don't need to init cs->colormod because the defaultstate did that for us
610 //cs->colormod[0] = cs->colormod[1] = cs->colormod[2] = 32;
611 val = PRVM_GETEDICTFIELDVALUE(ent, eval_colormod);
612 if (val->vector[0] || val->vector[1] || val->vector[2])
614 i = (int)(val->vector[0] * 32.0f);cs->colormod[0] = bound(0, i, 255);
615 i = (int)(val->vector[1] * 32.0f);cs->colormod[1] = bound(0, i, 255);
616 i = (int)(val->vector[2] * 32.0f);cs->colormod[2] = bound(0, i, 255);
619 cs->modelindex = modelindex;
622 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_alpha)->_float * 255.0f);
626 cs->alpha = (unsigned char)bound(0, i, 255);
629 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_renderamt)->_float);
633 cs->alpha = (unsigned char)bound(0, i, 255);
637 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_scale)->_float * 16.0f);
641 cs->scale = (unsigned char)bound(0, i, 255);
645 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_glow_color)->_float);
647 cs->glowcolor = (int)f;
649 if (PRVM_GETEDICTFIELDVALUE(ent, eval_fullbright)->_float)
650 cs->effects |= EF_FULLBRIGHT;
652 if (ent->fields.server->movetype == MOVETYPE_STEP)
653 cs->flags |= RENDER_STEP;
654 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)
655 cs->flags |= RENDER_LOWPRECISION;
656 if (ent->fields.server->colormap >= 1024)
657 cs->flags |= RENDER_COLORMAPPED;
658 if (cs->viewmodelforclient)
659 cs->flags |= RENDER_VIEWMODEL; // show relative to the view
661 cs->light[0] = light[0];
662 cs->light[1] = light[1];
663 cs->light[2] = light[2];
664 cs->light[3] = light[3];
665 cs->lightstyle = lightstyle;
666 cs->lightpflags = lightpflags;
668 cs->specialvisibilityradius = specialvisibilityradius;
670 // calculate the visible box of this entity (don't use the physics box
671 // as that is often smaller than a model, and would not count
672 // specialvisibilityradius)
673 if ((model = sv.models[modelindex]))
675 float scale = cs->scale * (1.0f / 16.0f);
676 if (cs->angles[0] || cs->angles[2]) // pitch and roll
678 VectorMA(cs->origin, scale, model->rotatedmins, cullmins);
679 VectorMA(cs->origin, scale, model->rotatedmaxs, cullmaxs);
681 else if (cs->angles[1])
683 VectorMA(cs->origin, scale, model->yawmins, cullmins);
684 VectorMA(cs->origin, scale, model->yawmaxs, cullmaxs);
688 VectorMA(cs->origin, scale, model->normalmins, cullmins);
689 VectorMA(cs->origin, scale, model->normalmaxs, cullmaxs);
694 // if there is no model (or it could not be loaded), use the physics box
695 VectorAdd(cs->origin, ent->fields.server->mins, cullmins);
696 VectorAdd(cs->origin, ent->fields.server->maxs, cullmaxs);
698 if (specialvisibilityradius)
700 cullmins[0] = min(cullmins[0], cs->origin[0] - specialvisibilityradius);
701 cullmins[1] = min(cullmins[1], cs->origin[1] - specialvisibilityradius);
702 cullmins[2] = min(cullmins[2], cs->origin[2] - specialvisibilityradius);
703 cullmaxs[0] = max(cullmaxs[0], cs->origin[0] + specialvisibilityradius);
704 cullmaxs[1] = max(cullmaxs[1], cs->origin[1] + specialvisibilityradius);
705 cullmaxs[2] = max(cullmaxs[2], cs->origin[2] + specialvisibilityradius);
707 if (!VectorCompare(cullmins, ent->priv.server->cullmins) || !VectorCompare(cullmaxs, ent->priv.server->cullmaxs))
709 VectorCopy(cullmins, ent->priv.server->cullmins);
710 VectorCopy(cullmaxs, ent->priv.server->cullmaxs);
711 ent->priv.server->pvs_numclusters = -1;
712 if (sv.worldmodel && sv.worldmodel->brush.FindBoxClusters)
714 i = sv.worldmodel->brush.FindBoxClusters(sv.worldmodel, cullmins, cullmaxs, MAX_ENTITYCLUSTERS, ent->priv.server->pvs_clusterlist);
715 if (i <= MAX_ENTITYCLUSTERS)
716 ent->priv.server->pvs_numclusters = i;
723 void SV_PrepareEntitiesForSending(void)
727 // send all entities that touch the pvs
729 sendentitiesindex[0] = NULL;
730 memset(sendentitiesindex, 0, prog->num_edicts * sizeof(entity_state_t *));
731 for (e = 1, ent = PRVM_NEXT_EDICT(prog->edicts);e < prog->num_edicts;e++, ent = PRVM_NEXT_EDICT(ent))
733 if (!ent->priv.server->free && SV_PrepareEntityForSending(ent, sendentities + numsendentities, e))
735 sendentitiesindex[e] = sendentities + numsendentities;
741 static int sententitiesmark = 0;
742 static int sententities[MAX_EDICTS];
743 static int sententitiesconsideration[MAX_EDICTS];
744 static int sv_writeentitiestoclient_culled_pvs;
745 static int sv_writeentitiestoclient_culled_trace;
746 static int sv_writeentitiestoclient_visibleentities;
747 static int sv_writeentitiestoclient_totalentities;
748 //static entity_frame_t sv_writeentitiestoclient_entityframe;
749 static int sv_writeentitiestoclient_clentnum;
750 static vec3_t sv_writeentitiestoclient_testeye;
751 static client_t *sv_writeentitiestoclient_client;
753 void SV_MarkWriteEntityStateToClient(entity_state_t *s)
760 if (sententitiesconsideration[s->number] == sententitiesmark)
762 sententitiesconsideration[s->number] = sententitiesmark;
763 sv_writeentitiestoclient_totalentities++;
765 if (s->customizeentityforclient)
767 prog->globals.server->self = s->number;
768 prog->globals.server->other = sv_writeentitiestoclient_clentnum;
769 PRVM_ExecuteProgram(s->customizeentityforclient, "customizeentityforclient: NULL function");
770 if(!PRVM_G_FLOAT(OFS_RETURN) || !SV_PrepareEntityForSending(PRVM_EDICT_NUM(s->number), s, s->number))
774 // never reject player
775 if (s->number != sv_writeentitiestoclient_clentnum)
777 // check various rejection conditions
778 if (s->nodrawtoclient == sv_writeentitiestoclient_clentnum)
780 if (s->drawonlytoclient && s->drawonlytoclient != sv_writeentitiestoclient_clentnum)
782 if (s->effects & EF_NODRAW)
784 // LordHavoc: only send entities with a model or important effects
785 if (!s->modelindex && s->specialvisibilityradius == 0)
788 // viewmodels don't have visibility checking
789 if (s->viewmodelforclient)
791 if (s->viewmodelforclient != sv_writeentitiestoclient_clentnum)
794 else if (s->tagentity)
796 // tag attached entities simply check their parent
797 if (!sendentitiesindex[s->tagentity])
799 SV_MarkWriteEntityStateToClient(sendentitiesindex[s->tagentity]);
800 if (sententities[s->tagentity] != sententitiesmark)
803 // always send world submodels in newer protocols because they don't
804 // generate much traffic (in old protocols they hog bandwidth)
805 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)))
807 // entity has survived every check so far, check if visible
808 ed = PRVM_EDICT_NUM(s->number);
810 // if not touching a visible leaf
811 if (sv_cullentities_pvs.integer && sv_writeentitiestoclient_pvsbytes)
813 if (ed->priv.server->pvs_numclusters < 0)
815 // entity too big for clusters list
816 if (sv.worldmodel && sv.worldmodel->brush.BoxTouchingPVS && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, sv_writeentitiestoclient_pvs, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
818 sv_writeentitiestoclient_culled_pvs++;
825 // check cached clusters list
826 for (i = 0;i < ed->priv.server->pvs_numclusters;i++)
827 if (CHECKPVSBIT(sv_writeentitiestoclient_pvs, ed->priv.server->pvs_clusterlist[i]))
829 if (i == ed->priv.server->pvs_numclusters)
831 sv_writeentitiestoclient_culled_pvs++;
837 // or not seen by random tracelines
838 if (sv_cullentities_trace.integer && !isbmodel)
840 // LordHavoc: test center first
841 testorigin[0] = (ed->priv.server->cullmins[0] + ed->priv.server->cullmaxs[0]) * 0.5f;
842 testorigin[1] = (ed->priv.server->cullmins[1] + ed->priv.server->cullmaxs[1]) * 0.5f;
843 testorigin[2] = (ed->priv.server->cullmins[2] + ed->priv.server->cullmaxs[2]) * 0.5f;
844 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
845 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
846 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
849 // LordHavoc: test random offsets, to maximize chance of detection
850 testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]);
851 testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]);
852 testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]);
853 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
854 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
855 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
858 if (s->specialvisibilityradius)
860 // LordHavoc: test random offsets, to maximize chance of detection
861 testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]);
862 testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]);
863 testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]);
864 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
865 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
866 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
870 if (realtime > sv_writeentitiestoclient_client->visibletime[s->number])
872 sv_writeentitiestoclient_culled_trace++;
879 // this just marks it for sending
880 // FIXME: it would be more efficient to send here, but the entity
881 // compressor isn't that flexible
882 sv_writeentitiestoclient_visibleentities++;
883 sententities[s->number] = sententitiesmark;
886 entity_state_t sendstates[MAX_EDICTS];
887 extern int csqc_clent;
889 void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t *msg, int *stats)
891 int i, numsendstates;
894 // if there isn't enough space to accomplish anything, skip it
895 if (msg->cursize + 25 > msg->maxsize)
898 sv_writeentitiestoclient_client = client;
900 sv_writeentitiestoclient_culled_pvs = 0;
901 sv_writeentitiestoclient_culled_trace = 0;
902 sv_writeentitiestoclient_visibleentities = 0;
903 sv_writeentitiestoclient_totalentities = 0;
905 // find the client's PVS
906 // the real place being tested from
907 VectorAdd(clent->fields.server->origin, clent->fields.server->view_ofs, sv_writeentitiestoclient_testeye);
908 sv_writeentitiestoclient_pvsbytes = 0;
909 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
910 sv_writeentitiestoclient_pvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, sv_writeentitiestoclient_testeye, 8, sv_writeentitiestoclient_pvs, sizeof(sv_writeentitiestoclient_pvs));
912 csqc_clent = sv_writeentitiestoclient_clentnum = PRVM_EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes
916 for (i = 0;i < numsendentities;i++)
917 SV_MarkWriteEntityStateToClient(sendentities + i);
920 for (i = 0;i < numsendentities;i++)
922 if (sententities[sendentities[i].number] == sententitiesmark)
924 s = &sendstates[numsendstates++];
925 *s = sendentities[i];
926 if (s->exteriormodelforclient && s->exteriormodelforclient == sv_writeentitiestoclient_clentnum)
927 s->flags |= RENDER_EXTERIORMODEL;
931 if (sv_cullentities_stats.integer)
932 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);
934 EntityFrameCSQC_WriteFrame(msg, numsendstates, sendstates);
936 if (client->entitydatabase5)
937 EntityFrame5_WriteFrame(msg, client->entitydatabase5, numsendstates, sendstates, client - svs.clients + 1, stats, client->movesequence);
938 else if (client->entitydatabase4)
939 EntityFrame4_WriteFrame(msg, client->entitydatabase4, numsendstates, sendstates);
940 else if (client->entitydatabase)
941 EntityFrame_WriteFrame(msg, client->entitydatabase, numsendstates, sendstates, client - svs.clients + 1);
943 EntityFrameQuake_WriteFrame(msg, numsendstates, sendstates);
952 void SV_CleanupEnts (void)
957 ent = PRVM_NEXT_EDICT(prog->edicts);
958 for (e=1 ; e<prog->num_edicts ; e++, ent = PRVM_NEXT_EDICT(ent))
959 ent->fields.server->effects = (int)ent->fields.server->effects & ~EF_MUZZLEFLASH;
964 SV_WriteClientdataToMessage
968 void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
980 // send a damage message
982 if (ent->fields.server->dmg_take || ent->fields.server->dmg_save)
984 other = PRVM_PROG_TO_EDICT(ent->fields.server->dmg_inflictor);
985 MSG_WriteByte (msg, svc_damage);
986 MSG_WriteByte (msg, (int)ent->fields.server->dmg_save);
987 MSG_WriteByte (msg, (int)ent->fields.server->dmg_take);
988 for (i=0 ; i<3 ; i++)
989 MSG_WriteCoord (msg, other->fields.server->origin[i] + 0.5*(other->fields.server->mins[i] + other->fields.server->maxs[i]), sv.protocol);
991 ent->fields.server->dmg_take = 0;
992 ent->fields.server->dmg_save = 0;
996 // send the current viewpos offset from the view entity
998 SV_SetIdealPitch (); // how much to look up / down ideally
1000 // a fixangle might get lost in a dropped packet. Oh well.
1001 if ( ent->fields.server->fixangle )
1003 MSG_WriteByte (msg, svc_setangle);
1004 for (i=0 ; i < 3 ; i++)
1005 MSG_WriteAngle (msg, ent->fields.server->angles[i], sv.protocol);
1006 ent->fields.server->fixangle = 0;
1009 // stuff the sigil bits into the high bits of items for sbar, or else
1011 val = PRVM_GETEDICTFIELDVALUE(ent, eval_items2);
1012 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
1013 items = (int)ent->fields.server->items | ((int)val->_float << 23);
1015 items = (int)ent->fields.server->items | ((int)prog->globals.server->serverflags << 28);
1017 VectorClear(punchvector);
1018 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_punchvector)))
1019 VectorCopy(val->vector, punchvector);
1021 // cache weapon model name and index in client struct to save time
1022 // (this search can be almost 1% of cpu time!)
1023 s = PRVM_GetString(ent->fields.server->weaponmodel);
1024 if (strcmp(s, client->weaponmodel))
1026 strlcpy(client->weaponmodel, s, sizeof(client->weaponmodel));
1027 client->weaponmodelindex = SV_ModelIndex(s, 1);
1031 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_viewzoom)))
1032 viewzoom = (int)(val->_float * 255.0f);
1038 if ((int)ent->fields.server->flags & FL_ONGROUND)
1039 bits |= SU_ONGROUND;
1040 if (ent->fields.server->waterlevel >= 2)
1042 if (ent->fields.server->idealpitch)
1043 bits |= SU_IDEALPITCH;
1045 for (i=0 ; i<3 ; i++)
1047 if (ent->fields.server->punchangle[i])
1048 bits |= (SU_PUNCH1<<i);
1049 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
1051 bits |= (SU_PUNCHVEC1<<i);
1052 if (ent->fields.server->velocity[i])
1053 bits |= (SU_VELOCITY1<<i);
1056 memset(stats, 0, sizeof(int[MAX_CL_STATS]));
1057 stats[STAT_VIEWHEIGHT] = (int)ent->fields.server->view_ofs[2];
1058 stats[STAT_ITEMS] = items;
1059 stats[STAT_WEAPONFRAME] = (int)ent->fields.server->weaponframe;
1060 stats[STAT_ARMOR] = (int)ent->fields.server->armorvalue;
1061 stats[STAT_WEAPON] = client->weaponmodelindex;
1062 stats[STAT_HEALTH] = (int)ent->fields.server->health;
1063 stats[STAT_AMMO] = (int)ent->fields.server->currentammo;
1064 stats[STAT_SHELLS] = (int)ent->fields.server->ammo_shells;
1065 stats[STAT_NAILS] = (int)ent->fields.server->ammo_nails;
1066 stats[STAT_ROCKETS] = (int)ent->fields.server->ammo_rockets;
1067 stats[STAT_CELLS] = (int)ent->fields.server->ammo_cells;
1068 stats[STAT_ACTIVEWEAPON] = (int)ent->fields.server->weapon;
1069 stats[STAT_VIEWZOOM] = viewzoom;
1070 // the QC bumps these itself by sending svc_'s, so we have to keep them
1071 // zero or they'll be corrected by the engine
1072 //stats[STAT_TOTALSECRETS] = prog->globals.server->total_secrets;
1073 //stats[STAT_TOTALMONSTERS] = prog->globals.server->total_monsters;
1074 //stats[STAT_SECRETS] = prog->globals.server->found_secrets;
1075 //stats[STAT_MONSTERS] = prog->globals.server->killed_monsters;
1077 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)
1079 if (stats[STAT_VIEWHEIGHT] != DEFAULT_VIEWHEIGHT) bits |= SU_VIEWHEIGHT;
1081 if (stats[STAT_WEAPONFRAME]) bits |= SU_WEAPONFRAME;
1082 if (stats[STAT_ARMOR]) bits |= SU_ARMOR;
1084 // FIXME: which protocols support this? does PROTOCOL_DARKPLACES3 support viewzoom?
1085 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
1086 if (viewzoom != 255)
1087 bits |= SU_VIEWZOOM;
1092 if (bits >= 16777216)
1096 MSG_WriteByte (msg, svc_clientdata);
1097 MSG_WriteShort (msg, bits);
1098 if (bits & SU_EXTEND1)
1099 MSG_WriteByte(msg, bits >> 16);
1100 if (bits & SU_EXTEND2)
1101 MSG_WriteByte(msg, bits >> 24);
1103 if (bits & SU_VIEWHEIGHT)
1104 MSG_WriteChar (msg, stats[STAT_VIEWHEIGHT]);
1106 if (bits & SU_IDEALPITCH)
1107 MSG_WriteChar (msg, (int)ent->fields.server->idealpitch);
1109 for (i=0 ; i<3 ; i++)
1111 if (bits & (SU_PUNCH1<<i))
1113 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1114 MSG_WriteChar(msg, (int)ent->fields.server->punchangle[i]);
1116 MSG_WriteAngle16i(msg, ent->fields.server->punchangle[i]);
1118 if (bits & (SU_PUNCHVEC1<<i))
1120 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1121 MSG_WriteCoord16i(msg, punchvector[i]);
1123 MSG_WriteCoord32f(msg, punchvector[i]);
1125 if (bits & (SU_VELOCITY1<<i))
1127 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1128 MSG_WriteChar(msg, (int)(ent->fields.server->velocity[i] * (1.0f / 16.0f)));
1130 MSG_WriteCoord32f(msg, ent->fields.server->velocity[i]);
1134 if (bits & SU_ITEMS)
1135 MSG_WriteLong (msg, stats[STAT_ITEMS]);
1137 if (sv.protocol == PROTOCOL_DARKPLACES5)
1139 if (bits & SU_WEAPONFRAME)
1140 MSG_WriteShort (msg, stats[STAT_WEAPONFRAME]);
1141 if (bits & SU_ARMOR)
1142 MSG_WriteShort (msg, stats[STAT_ARMOR]);
1143 if (bits & SU_WEAPON)
1144 MSG_WriteShort (msg, stats[STAT_WEAPON]);
1145 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1146 MSG_WriteShort (msg, stats[STAT_AMMO]);
1147 MSG_WriteShort (msg, stats[STAT_SHELLS]);
1148 MSG_WriteShort (msg, stats[STAT_NAILS]);
1149 MSG_WriteShort (msg, stats[STAT_ROCKETS]);
1150 MSG_WriteShort (msg, stats[STAT_CELLS]);
1151 MSG_WriteShort (msg, stats[STAT_ACTIVEWEAPON]);
1152 if (bits & SU_VIEWZOOM)
1153 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1155 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)
1157 if (bits & SU_WEAPONFRAME)
1158 MSG_WriteByte (msg, stats[STAT_WEAPONFRAME]);
1159 if (bits & SU_ARMOR)
1160 MSG_WriteByte (msg, stats[STAT_ARMOR]);
1161 if (bits & SU_WEAPON)
1162 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1163 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1164 MSG_WriteByte (msg, stats[STAT_AMMO]);
1165 MSG_WriteByte (msg, stats[STAT_SHELLS]);
1166 MSG_WriteByte (msg, stats[STAT_NAILS]);
1167 MSG_WriteByte (msg, stats[STAT_ROCKETS]);
1168 MSG_WriteByte (msg, stats[STAT_CELLS]);
1169 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_NEXUIZ)
1171 for (i = 0;i < 32;i++)
1172 if (stats[STAT_WEAPON] & (1<<i))
1174 MSG_WriteByte (msg, i);
1177 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1178 if (bits & SU_VIEWZOOM)
1180 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1181 MSG_WriteByte (msg, bound(0, stats[STAT_VIEWZOOM], 255));
1183 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1189 =======================
1190 SV_SendClientDatagram
1191 =======================
1193 static unsigned char sv_sendclientdatagram_buf[NET_MAXMESSAGE]; // FIXME?
1194 void SV_SendClientDatagram (client_t *client)
1196 int rate, maxrate, maxsize, maxsize2;
1198 int stats[MAX_CL_STATS];
1200 if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP && !sv_ratelimitlocalplayer.integer)
1202 // for good singleplayer, send huge packets
1203 maxsize = sizeof(sv_sendclientdatagram_buf);
1204 maxsize2 = sizeof(sv_sendclientdatagram_buf);
1206 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)
1208 // no rate limiting support on older protocols because dp protocols
1209 // 1-4 kick the client off if they overflow, and quake protocol shows
1210 // less than the full entity set if rate limited
1216 // PROTOCOL_DARKPLACES5 and later support packet size limiting of updates
1217 maxrate = bound(NET_MINRATE, sv_maxrate.integer, NET_MAXRATE);
1218 if (sv_maxrate.integer != maxrate)
1219 Cvar_SetValueQuick(&sv_maxrate, maxrate);
1221 // this rate limiting does not understand sys_ticrate 0
1222 // (but no one should be running that on a server!)
1223 rate = bound(NET_MINRATE, client->rate, maxrate);
1224 rate = (int)(client->rate * sys_ticrate.value);
1225 maxsize = bound(100, rate, 1400);
1229 msg.data = sv_sendclientdatagram_buf;
1230 msg.maxsize = maxsize;
1233 if (host_client->spawned)
1235 MSG_WriteByte (&msg, svc_time);
1236 MSG_WriteFloat (&msg, sv.time);
1238 // add the client specific data to the datagram
1239 SV_WriteClientdataToMessage (client, client->edict, &msg, stats);
1240 VM_SV_WriteAutoSentStats (client, client->edict, &msg, stats);
1241 SV_WriteEntitiesToClient (client, client->edict, &msg, stats);
1243 // expand packet size to allow effects to go over the rate limit
1244 // (dropping them is FAR too ugly)
1245 msg.maxsize = maxsize2;
1247 // copy the server datagram if there is space
1248 // FIXME: put in delayed queue of effects to send
1249 if (sv.datagram.cursize > 0 && msg.cursize + sv.datagram.cursize <= msg.maxsize)
1250 SZ_Write (&msg, sv.datagram.data, sv.datagram.cursize);
1252 else if (realtime > client->keepalivetime)
1254 // the player isn't totally in the game yet
1255 // send small keepalive messages if too much time has passed
1256 client->keepalivetime = realtime + 5;
1257 MSG_WriteChar (&msg, svc_nop);
1260 // send the datagram
1261 NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol);
1265 =======================
1266 SV_UpdateToReliableMessages
1267 =======================
1269 void SV_UpdateToReliableMessages (void)
1278 // check for changes to be sent over the reliable streams
1279 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1281 // update the host_client fields we care about according to the entity fields
1282 host_client->edict = PRVM_EDICT_NUM(i+1);
1285 name = PRVM_GetString(host_client->edict->fields.server->netname);
1288 // always point the string back at host_client->name to keep it safe
1289 strlcpy (host_client->name, name, sizeof (host_client->name));
1290 host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
1291 if (strcmp(host_client->old_name, host_client->name))
1293 if (host_client->spawned)
1294 SV_BroadcastPrintf("%s changed name to %s\n", host_client->old_name, host_client->name);
1295 strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
1296 // send notification to all clients
1297 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
1298 MSG_WriteByte (&sv.reliable_datagram, i);
1299 MSG_WriteString (&sv.reliable_datagram, host_client->name);
1302 // DP_SV_CLIENTCOLORS
1303 // this is always found (since it's added by the progs loader)
1304 if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_clientcolors)))
1305 host_client->colors = (int)val->_float;
1306 if (host_client->old_colors != host_client->colors)
1308 host_client->old_colors = host_client->colors;
1309 // send notification to all clients
1310 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1311 MSG_WriteByte (&sv.reliable_datagram, i);
1312 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1315 // NEXUIZ_PLAYERMODEL
1316 if( eval_playermodel ) {
1317 model = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string);
1320 // always point the string back at host_client->name to keep it safe
1321 strlcpy (host_client->playermodel, model, sizeof (host_client->playermodel));
1322 PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
1325 // NEXUIZ_PLAYERSKIN
1326 if( eval_playerskin ) {
1327 skin = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string);
1330 // always point the string back at host_client->name to keep it safe
1331 strlcpy (host_client->playerskin, skin, sizeof (host_client->playerskin));
1332 PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
1336 host_client->frags = (int)host_client->edict->fields.server->frags;
1337 if (host_client->old_frags != host_client->frags)
1339 host_client->old_frags = host_client->frags;
1340 // send notification to all clients
1341 MSG_WriteByte (&sv.reliable_datagram, svc_updatefrags);
1342 MSG_WriteByte (&sv.reliable_datagram, i);
1343 MSG_WriteShort (&sv.reliable_datagram, host_client->frags);
1347 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1348 if (client->netconnection)
1349 SZ_Write (&client->netconnection->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
1351 SZ_Clear (&sv.reliable_datagram);
1356 =======================
1357 SV_SendClientMessages
1358 =======================
1360 void SV_SendClientMessages (void)
1362 int i, prepared = false;
1364 if (sv.protocol == PROTOCOL_QUAKEWORLD)
1365 Sys_Error("SV_SendClientMessages: no quakeworld support\n");
1367 // update frags, names, etc
1368 SV_UpdateToReliableMessages();
1370 // build individual updates
1371 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1373 if (!host_client->active)
1375 if (!host_client->netconnection)
1378 if (host_client->netconnection->message.overflowed)
1380 SV_DropClient (true); // if the message couldn't send, kick off
1387 // only prepare entities once per frame
1388 SV_PrepareEntitiesForSending();
1390 SV_SendClientDatagram (host_client);
1393 // clear muzzle flashes
1399 ==============================================================================
1403 ==============================================================================
1412 int SV_ModelIndex(const char *s, int precachemode)
1414 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_MODELS);
1415 char filename[MAX_QPATH];
1419 //if (precachemode == 2)
1421 strlcpy(filename, s, sizeof(filename));
1422 for (i = 2;i < limit;i++)
1424 if (!sv.model_precache[i][0])
1428 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))
1430 Con_Printf("SV_ModelIndex(\"%s\"): precache_model can only be done in spawn functions\n", filename);
1433 if (precachemode == 1)
1434 Con_Printf("SV_ModelIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1435 strlcpy(sv.model_precache[i], filename, sizeof(sv.model_precache[i]));
1436 sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, false);
1437 if (sv.state != ss_loading)
1439 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1440 MSG_WriteShort(&sv.reliable_datagram, i);
1441 MSG_WriteString(&sv.reliable_datagram, filename);
1445 Con_Printf("SV_ModelIndex(\"%s\"): not precached\n", filename);
1448 if (!strcmp(sv.model_precache[i], filename))
1451 Con_Printf("SV_ModelIndex(\"%s\"): i (%i) == MAX_MODELS (%i)\n", filename, i, MAX_MODELS);
1461 int SV_SoundIndex(const char *s, int precachemode)
1463 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_SOUNDS);
1464 char filename[MAX_QPATH];
1468 //if (precachemode == 2)
1470 strlcpy(filename, s, sizeof(filename));
1471 for (i = 1;i < limit;i++)
1473 if (!sv.sound_precache[i][0])
1477 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))
1479 Con_Printf("SV_SoundIndex(\"%s\"): precache_sound can only be done in spawn functions\n", filename);
1482 if (precachemode == 1)
1483 Con_Printf("SV_SoundIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1484 strlcpy(sv.sound_precache[i], filename, sizeof(sv.sound_precache[i]));
1485 if (sv.state != ss_loading)
1487 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1488 MSG_WriteShort(&sv.reliable_datagram, i + 32768);
1489 MSG_WriteString(&sv.reliable_datagram, filename);
1493 Con_Printf("SV_SoundIndex(\"%s\"): not precached\n", filename);
1496 if (!strcmp(sv.sound_precache[i], filename))
1499 Con_Printf("SV_SoundIndex(\"%s\"): i (%i) == MAX_SOUNDS (%i)\n", filename, i, MAX_SOUNDS);
1509 void SV_CreateBaseline (void)
1511 int i, entnum, large;
1512 prvm_edict_t *svent;
1514 // LordHavoc: clear *all* states (note just active ones)
1515 for (entnum = 0;entnum < prog->max_edicts;entnum++)
1517 // get the current server version
1518 svent = PRVM_EDICT_NUM(entnum);
1520 // LordHavoc: always clear state values, whether the entity is in use or not
1521 svent->priv.server->baseline = defaultstate;
1523 if (svent->priv.server->free)
1525 if (entnum > svs.maxclients && !svent->fields.server->modelindex)
1528 // create entity baseline
1529 VectorCopy (svent->fields.server->origin, svent->priv.server->baseline.origin);
1530 VectorCopy (svent->fields.server->angles, svent->priv.server->baseline.angles);
1531 svent->priv.server->baseline.frame = (int)svent->fields.server->frame;
1532 svent->priv.server->baseline.skin = (int)svent->fields.server->skin;
1533 if (entnum > 0 && entnum <= svs.maxclients)
1535 svent->priv.server->baseline.colormap = entnum;
1536 svent->priv.server->baseline.modelindex = SV_ModelIndex("progs/player.mdl", 1);
1540 svent->priv.server->baseline.colormap = 0;
1541 svent->priv.server->baseline.modelindex = (int)svent->fields.server->modelindex;
1545 if (svent->priv.server->baseline.modelindex & 0xFF00 || svent->priv.server->baseline.frame & 0xFF00)
1548 // add to the message
1550 MSG_WriteByte (&sv.signon, svc_spawnbaseline2);
1552 MSG_WriteByte (&sv.signon, svc_spawnbaseline);
1553 MSG_WriteShort (&sv.signon, entnum);
1557 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.modelindex);
1558 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.frame);
1562 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.modelindex);
1563 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.frame);
1565 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.colormap);
1566 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.skin);
1567 for (i=0 ; i<3 ; i++)
1569 MSG_WriteCoord(&sv.signon, svent->priv.server->baseline.origin[i], sv.protocol);
1570 MSG_WriteAngle(&sv.signon, svent->priv.server->baseline.angles[i], sv.protocol);
1580 Grabs the current state of each client for saving across the
1581 transition to another level
1584 void SV_SaveSpawnparms (void)
1588 svs.serverflags = (int)prog->globals.server->serverflags;
1590 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1592 if (!host_client->active)
1595 // call the progs to get default spawn parms for the new client
1596 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1597 PRVM_ExecuteProgram (prog->globals.server->SetChangeParms, "QC function SetChangeParms is missing");
1598 for (j=0 ; j<NUM_SPAWN_PARMS ; j++)
1599 host_client->spawn_parms[j] = (&prog->globals.server->parm1)[j];
1603 void SV_IncreaseEdicts(void)
1607 int oldmax_edicts = prog->max_edicts;
1608 void *oldedictsengineprivate = prog->edictprivate;
1609 void *oldedictsfields = prog->edictsfields;
1610 void *oldmoved_edicts = sv.moved_edicts;
1612 if (prog->max_edicts >= MAX_EDICTS)
1615 // links don't survive the transition, so unlink everything
1616 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1618 if (!ent->priv.server->free)
1619 SV_UnlinkEdict(prog->edicts + i);
1620 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
1624 prog->max_edicts = min(prog->max_edicts + 256, MAX_EDICTS);
1625 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
1626 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);
1627 sv.moved_edicts = PR_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1629 memcpy(prog->edictprivate, oldedictsengineprivate, oldmax_edicts * sizeof(edict_engineprivate_t));
1630 memcpy(prog->edictsfields, oldedictsfields, oldmax_edicts * prog->edict_size);
1632 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1634 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
1635 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
1636 // link every entity except world
1637 if (!ent->priv.server->free)
1638 SV_LinkEdict(ent, false);
1641 PR_Free(oldedictsengineprivate);
1642 PR_Free(oldedictsfields);
1643 PR_Free(oldmoved_edicts);
1650 This is called at the start of each level
1653 extern float scr_centertime_off;
1655 void SV_SpawnServer (const char *server)
1660 model_t *worldmodel;
1661 char modelname[sizeof(sv.modelname)];
1663 Con_DPrintf("SpawnServer: %s\n", server);
1665 if (cls.state != ca_dedicated)
1666 SCR_BeginLoadingPlaque();
1668 dpsnprintf (modelname, sizeof(modelname), "maps/%s.bsp", server);
1669 worldmodel = Mod_ForName(modelname, false, true, true);
1670 if (!worldmodel || !worldmodel->TraceBox)
1672 Con_Printf("Couldn't load map %s\n", modelname);
1676 // let's not have any servers with no name
1677 if (hostname.string[0] == 0)
1678 Cvar_Set ("hostname", "UNNAMED");
1679 scr_centertime_off = 0;
1681 svs.changelevel_issued = false; // now safe to issue another
1683 // make the map a required file for clients
1684 Curl_ClearRequirements();
1685 Curl_RequireFile(modelname);
1688 // tell all connected clients that we are going to a new level
1693 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
1695 if (client->netconnection)
1697 MSG_WriteByte(&client->netconnection->message, svc_stufftext);
1698 MSG_WriteString(&client->netconnection->message, "reconnect\n");
1705 NetConn_OpenServerPorts(true);
1709 // make cvars consistant
1712 Cvar_SetValue ("deathmatch", 0);
1713 // LordHavoc: it can be useful to have skills outside the range 0-3...
1714 //current_skill = bound(0, (int)(skill.value + 0.5), 3);
1715 //Cvar_SetValue ("skill", (float)current_skill);
1716 current_skill = (int)(skill.value + 0.5);
1719 // set up the new server
1721 memset (&sv, 0, sizeof(sv));
1722 // if running a local client, make sure it doesn't try to access the last
1723 // level's data which is no longer valiud
1730 strlcpy (sv.name, server, sizeof (sv.name));
1732 sv.protocol = Protocol_EnumForName(sv_protocolname.string);
1733 if (sv.protocol == PROTOCOL_UNKNOWN)
1736 Protocol_Names(buffer, sizeof(buffer));
1737 Con_Printf("Unknown sv_protocolname \"%s\", valid values are:\n%s\n", sv_protocolname.string, buffer);
1738 sv.protocol = PROTOCOL_QUAKE;
1743 // load progs to get entity field count
1744 //PR_LoadProgs ( sv_progs.string );
1746 // allocate server memory
1747 /*// start out with just enough room for clients and a reasonable estimate of entities
1748 prog->max_edicts = max(svs.maxclients + 1, 512);
1749 prog->max_edicts = min(prog->max_edicts, MAX_EDICTS);
1751 // prvm_edict_t structures (hidden from progs)
1752 prog->edicts = PR_Alloc(MAX_EDICTS * sizeof(prvm_edict_t));
1753 // engine private structures (hidden from progs)
1754 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
1755 // progs fields, often accessed by server
1756 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);*/
1757 // used by PushMove to move back pushed entities
1758 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1759 /*for (i = 0;i < prog->max_edicts;i++)
1761 ent = prog->edicts + i;
1762 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
1763 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
1766 // reset client csqc entity versions right away.
1767 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1768 EntityFrameCSQC_InitClientVersions(i, true);
1770 sv.datagram.maxsize = sizeof(sv.datagram_buf);
1771 sv.datagram.cursize = 0;
1772 sv.datagram.data = sv.datagram_buf;
1774 sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf);
1775 sv.reliable_datagram.cursize = 0;
1776 sv.reliable_datagram.data = sv.reliable_datagram_buf;
1778 sv.signon.maxsize = sizeof(sv.signon_buf);
1779 sv.signon.cursize = 0;
1780 sv.signon.data = sv.signon_buf;
1782 // leave slots at start for clients only
1783 //prog->num_edicts = svs.maxclients+1;
1785 sv.state = ss_loading;
1786 prog->allowworldwrites = true;
1789 *prog->time = sv.time = 1.0;
1792 worldmodel->used = true;
1794 strlcpy (sv.name, server, sizeof (sv.name));
1795 strlcpy(sv.modelname, modelname, sizeof(sv.modelname));
1796 sv.worldmodel = worldmodel;
1797 sv.models[1] = sv.worldmodel;
1800 // clear world interaction links
1804 strlcpy(sv.sound_precache[0], "", sizeof(sv.sound_precache[0]));
1806 strlcpy(sv.model_precache[0], "", sizeof(sv.model_precache[0]));
1807 strlcpy(sv.model_precache[1], sv.modelname, sizeof(sv.model_precache[1]));
1808 for (i = 1;i < sv.worldmodel->brush.numsubmodels;i++)
1810 dpsnprintf(sv.model_precache[i+1], sizeof(sv.model_precache[i+1]), "*%i", i);
1811 sv.models[i+1] = Mod_ForName (sv.model_precache[i+1], false, false, false);
1815 // load the rest of the entities
1817 // AK possible hack since num_edicts is still 0
1818 ent = PRVM_EDICT_NUM(0);
1819 memset (ent->fields.server, 0, prog->progs->entityfields * 4);
1820 ent->priv.server->free = false;
1821 ent->fields.server->model = PRVM_SetEngineString(sv.modelname);
1822 ent->fields.server->modelindex = 1; // world model
1823 ent->fields.server->solid = SOLID_BSP;
1824 ent->fields.server->movetype = MOVETYPE_PUSH;
1827 prog->globals.server->coop = coop.integer;
1829 prog->globals.server->deathmatch = deathmatch.integer;
1831 prog->globals.server->mapname = PRVM_SetEngineString(sv.name);
1833 // serverflags are for cross level information (sigils)
1834 prog->globals.server->serverflags = svs.serverflags;
1836 // we need to reset the spawned flag on all connected clients here so that
1837 // their thinks don't run during startup (before PutClientInServer)
1838 // we also need to set up the client entities now
1839 // and we need to set the ->edict pointers to point into the progs edicts
1840 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1842 host_client->spawned = false;
1843 host_client->edict = PRVM_EDICT_NUM(i + 1);
1844 PRVM_ED_ClearEdict(host_client->edict);
1847 // load replacement entity file if found
1848 if (sv_entpatch.integer && (entities = (char *)FS_LoadFile(va("maps/%s.ent", sv.name), tempmempool, true, NULL)))
1850 Con_Printf("Loaded maps/%s.ent\n", sv.name);
1851 PRVM_ED_LoadFromFile (entities);
1855 PRVM_ED_LoadFromFile (sv.worldmodel->brush.entities);
1858 // LordHavoc: clear world angles (to fix e3m3.bsp)
1859 VectorClear(prog->edicts->fields.server->angles);
1861 // all setup is completed, any further precache statements are errors
1862 sv.state = ss_active;
1863 prog->allowworldwrites = false;
1865 // run two frames to allow everything to settle
1866 for (i = 0;i < 2;i++)
1874 // create a baseline for more efficient communications
1875 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1876 SV_CreateBaseline ();
1878 // send serverinfo to all connected clients, and set up botclients coming back from a level change
1879 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1881 if (!host_client->active)
1883 if (host_client->netconnection)
1884 SV_SendServerinfo(host_client);
1888 // if client is a botclient coming from a level change, we need to
1889 // set up client info that normally requires networking
1891 // copy spawn parms out of the client_t
1892 for (j=0 ; j< NUM_SPAWN_PARMS ; j++)
1893 (&prog->globals.server->parm1)[j] = host_client->spawn_parms[j];
1895 // call the spawn function
1896 host_client->clientconnectcalled = true;
1897 prog->globals.server->time = sv.time;
1898 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1899 PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
1900 PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
1901 host_client->spawned = true;
1905 Con_DPrint("Server spawned.\n");
1906 NetConn_Heartbeat (2);
1911 /////////////////////////////////////////////////////
1914 void SV_VM_CB_BeginIncreaseEdicts(void)
1919 PRVM_Free( sv.moved_edicts );
1920 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1922 // links don't survive the transition, so unlink everything
1923 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1925 if (!ent->priv.server->free)
1926 SV_UnlinkEdict(prog->edicts + i);
1927 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
1932 void SV_VM_CB_EndIncreaseEdicts(void)
1937 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1939 // link every entity except world
1940 if (!ent->priv.server->free)
1941 SV_LinkEdict(ent, false);
1945 void SV_VM_CB_InitEdict(prvm_edict_t *e)
1947 // LordHavoc: for consistency set these here
1948 int num = PRVM_NUM_FOR_EDICT(e) - 1;
1950 e->priv.server->move = false; // don't move on first frame
1952 if (num >= 0 && num < svs.maxclients)
1955 // set colormap and team on newly created player entity
1956 e->fields.server->colormap = num + 1;
1957 e->fields.server->team = (svs.clients[num].colors & 15) + 1;
1958 // set netname/clientcolors back to client values so that
1959 // DP_SV_CLIENTNAME and DP_SV_CLIENTCOLORS will not immediately
1961 e->fields.server->netname = PRVM_SetEngineString(svs.clients[num].name);
1962 if ((val = PRVM_GETEDICTFIELDVALUE(e, eval_clientcolors)))
1963 val->_float = svs.clients[num].colors;
1964 // NEXUIZ_PLAYERMODEL and NEXUIZ_PLAYERSKIN
1965 if( eval_playermodel )
1966 PRVM_GETEDICTFIELDVALUE(e, eval_playermodel)->string = PRVM_SetEngineString(svs.clients[num].playermodel);
1967 if( eval_playerskin )
1968 PRVM_GETEDICTFIELDVALUE(e, eval_playerskin)->string = PRVM_SetEngineString(svs.clients[num].playerskin);
1972 void SV_VM_CB_FreeEdict(prvm_edict_t *ed)
1974 SV_UnlinkEdict (ed); // unlink from world bsp
1976 ed->fields.server->model = 0;
1977 ed->fields.server->takedamage = 0;
1978 ed->fields.server->modelindex = 0;
1979 ed->fields.server->colormap = 0;
1980 ed->fields.server->skin = 0;
1981 ed->fields.server->frame = 0;
1982 VectorClear(ed->fields.server->origin);
1983 VectorClear(ed->fields.server->angles);
1984 ed->fields.server->nextthink = -1;
1985 ed->fields.server->solid = 0;
1988 void SV_VM_CB_CountEdicts(void)
1992 int active, models, solid, step;
1994 active = models = solid = step = 0;
1995 for (i=0 ; i<prog->num_edicts ; i++)
1997 ent = PRVM_EDICT_NUM(i);
1998 if (ent->priv.server->free)
2001 if (ent->fields.server->solid)
2003 if (ent->fields.server->model)
2005 if (ent->fields.server->movetype == MOVETYPE_STEP)
2009 Con_Printf("num_edicts:%3i\n", prog->num_edicts);
2010 Con_Printf("active :%3i\n", active);
2011 Con_Printf("view :%3i\n", models);
2012 Con_Printf("touch :%3i\n", solid);
2013 Con_Printf("step :%3i\n", step);
2016 qboolean SV_VM_CB_LoadEdict(prvm_edict_t *ent)
2018 // remove things from different skill levels or deathmatch
2019 if (gamemode != GAME_TRANSFUSION) //Transfusion does this in QC
2021 if (deathmatch.integer)
2023 if (((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
2028 else if ((current_skill <= 0 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_EASY ))
2029 || (current_skill == 1 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_MEDIUM))
2030 || (current_skill >= 2 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_HARD )))
2038 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)"};
2039 cvar_t nomonsters = {0, "nomonsters", "0", "unused cvar in quake, can be used by mods"};
2040 cvar_t gamecfg = {0, "gamecfg", "0", "unused cvar in quake, can be used by mods"};
2041 cvar_t scratch1 = {0, "scratch1", "0", "unused cvar in quake, can be used by mods"};
2042 cvar_t scratch2 = {0,"scratch2", "0", "unused cvar in quake, can be used by mods"};
2043 cvar_t scratch3 = {0, "scratch3", "0", "unused cvar in quake, can be used by mods"};
2044 cvar_t scratch4 = {0, "scratch4", "0", "unused cvar in quake, can be used by mods"};
2045 cvar_t savedgamecfg = {CVAR_SAVE, "savedgamecfg", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2046 cvar_t saved1 = {CVAR_SAVE, "saved1", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2047 cvar_t saved2 = {CVAR_SAVE, "saved2", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2048 cvar_t saved3 = {CVAR_SAVE, "saved3", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2049 cvar_t saved4 = {CVAR_SAVE, "saved4", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2050 cvar_t nehx00 = {0, "nehx00", "0", "nehahra data storage cvar (used in singleplayer)"};
2051 cvar_t nehx01 = {0, "nehx01", "0", "nehahra data storage cvar (used in singleplayer)"};
2052 cvar_t nehx02 = {0, "nehx02", "0", "nehahra data storage cvar (used in singleplayer)"};
2053 cvar_t nehx03 = {0, "nehx03", "0", "nehahra data storage cvar (used in singleplayer)"};
2054 cvar_t nehx04 = {0, "nehx04", "0", "nehahra data storage cvar (used in singleplayer)"};
2055 cvar_t nehx05 = {0, "nehx05", "0", "nehahra data storage cvar (used in singleplayer)"};
2056 cvar_t nehx06 = {0, "nehx06", "0", "nehahra data storage cvar (used in singleplayer)"};
2057 cvar_t nehx07 = {0, "nehx07", "0", "nehahra data storage cvar (used in singleplayer)"};
2058 cvar_t nehx08 = {0, "nehx08", "0", "nehahra data storage cvar (used in singleplayer)"};
2059 cvar_t nehx09 = {0, "nehx09", "0", "nehahra data storage cvar (used in singleplayer)"};
2060 cvar_t nehx10 = {0, "nehx10", "0", "nehahra data storage cvar (used in singleplayer)"};
2061 cvar_t nehx11 = {0, "nehx11", "0", "nehahra data storage cvar (used in singleplayer)"};
2062 cvar_t nehx12 = {0, "nehx12", "0", "nehahra data storage cvar (used in singleplayer)"};
2063 cvar_t nehx13 = {0, "nehx13", "0", "nehahra data storage cvar (used in singleplayer)"};
2064 cvar_t nehx14 = {0, "nehx14", "0", "nehahra data storage cvar (used in singleplayer)"};
2065 cvar_t nehx15 = {0, "nehx15", "0", "nehahra data storage cvar (used in singleplayer)"};
2066 cvar_t nehx16 = {0, "nehx16", "0", "nehahra data storage cvar (used in singleplayer)"};
2067 cvar_t nehx17 = {0, "nehx17", "0", "nehahra data storage cvar (used in singleplayer)"};
2068 cvar_t nehx18 = {0, "nehx18", "0", "nehahra data storage cvar (used in singleplayer)"};
2069 cvar_t nehx19 = {0, "nehx19", "0", "nehahra data storage cvar (used in singleplayer)"};
2070 cvar_t cutscene = {0, "cutscene", "1", "enables cutscenes in nehahra, can be used by other mods"};
2072 void SV_VM_Init(void)
2074 Cvar_RegisterVariable (&pr_checkextension);
2075 Cvar_RegisterVariable (&nomonsters);
2076 Cvar_RegisterVariable (&gamecfg);
2077 Cvar_RegisterVariable (&scratch1);
2078 Cvar_RegisterVariable (&scratch2);
2079 Cvar_RegisterVariable (&scratch3);
2080 Cvar_RegisterVariable (&scratch4);
2081 Cvar_RegisterVariable (&savedgamecfg);
2082 Cvar_RegisterVariable (&saved1);
2083 Cvar_RegisterVariable (&saved2);
2084 Cvar_RegisterVariable (&saved3);
2085 Cvar_RegisterVariable (&saved4);
2086 // LordHavoc: Nehahra uses these to pass data around cutscene demos
2087 if (gamemode == GAME_NEHAHRA)
2089 Cvar_RegisterVariable (&nehx00);
2090 Cvar_RegisterVariable (&nehx01);
2091 Cvar_RegisterVariable (&nehx02);
2092 Cvar_RegisterVariable (&nehx03);
2093 Cvar_RegisterVariable (&nehx04);
2094 Cvar_RegisterVariable (&nehx05);
2095 Cvar_RegisterVariable (&nehx06);
2096 Cvar_RegisterVariable (&nehx07);
2097 Cvar_RegisterVariable (&nehx08);
2098 Cvar_RegisterVariable (&nehx09);
2099 Cvar_RegisterVariable (&nehx10);
2100 Cvar_RegisterVariable (&nehx11);
2101 Cvar_RegisterVariable (&nehx12);
2102 Cvar_RegisterVariable (&nehx13);
2103 Cvar_RegisterVariable (&nehx14);
2104 Cvar_RegisterVariable (&nehx15);
2105 Cvar_RegisterVariable (&nehx16);
2106 Cvar_RegisterVariable (&nehx17);
2107 Cvar_RegisterVariable (&nehx18);
2108 Cvar_RegisterVariable (&nehx19);
2110 Cvar_RegisterVariable (&cutscene); // for Nehahra but useful to other mods as well
2113 // LordHavoc: in an effort to eliminate time wasted on GetEdictFieldValue... these are defined as externs in progs.h
2130 int eval_buttonchat;
2132 int eval_glow_trail;
2133 int eval_glow_color;
2137 int eval_renderamt; // HalfLife support
2138 int eval_rendermode; // HalfLife support
2139 int eval_fullbright;
2140 int eval_ammo_shells1;
2141 int eval_ammo_nails1;
2142 int eval_ammo_lava_nails;
2143 int eval_ammo_rockets1;
2144 int eval_ammo_multi_rockets;
2145 int eval_ammo_cells1;
2146 int eval_ammo_plasma;
2147 int eval_idealpitch;
2148 int eval_pitch_speed;
2149 int eval_viewmodelforclient;
2150 int eval_nodrawtoclient;
2151 int eval_exteriormodeltoclient;
2152 int eval_drawonlytoclient;
2156 int eval_punchvector;
2158 int eval_clientcolors;
2159 int eval_tag_entity;
2165 int eval_cursor_active;
2166 int eval_cursor_screen;
2167 int eval_cursor_trace_start;
2168 int eval_cursor_trace_endpos;
2169 int eval_cursor_trace_ent;
2171 int eval_playermodel;
2172 int eval_playerskin;
2173 int eval_SendEntity;
2175 int eval_customizeentityforclient;
2176 int eval_dphitcontentsmask;
2178 int gval_trace_dpstartcontents;
2179 int gval_trace_dphitcontents;
2180 int gval_trace_dphitq3surfaceflags;
2181 int gval_trace_dphittexturename;
2183 mfunction_t *SV_PlayerPhysicsQC;
2184 mfunction_t *EndFrameQC;
2185 //KrimZon - SERVER COMMANDS IN QUAKEC
2186 mfunction_t *SV_ParseClientCommandQC;
2188 ddef_t *PRVM_ED_FindGlobal(const char *name);
2190 void SV_VM_FindEdictFieldOffsets(void)
2192 eval_gravity = PRVM_ED_FindFieldOffset("gravity");
2193 eval_button3 = PRVM_ED_FindFieldOffset("button3");
2194 eval_button4 = PRVM_ED_FindFieldOffset("button4");
2195 eval_button5 = PRVM_ED_FindFieldOffset("button5");
2196 eval_button6 = PRVM_ED_FindFieldOffset("button6");
2197 eval_button7 = PRVM_ED_FindFieldOffset("button7");
2198 eval_button8 = PRVM_ED_FindFieldOffset("button8");
2199 eval_button9 = PRVM_ED_FindFieldOffset("button9");
2200 eval_button10 = PRVM_ED_FindFieldOffset("button10");
2201 eval_button11 = PRVM_ED_FindFieldOffset("button11");
2202 eval_button12 = PRVM_ED_FindFieldOffset("button12");
2203 eval_button13 = PRVM_ED_FindFieldOffset("button13");
2204 eval_button14 = PRVM_ED_FindFieldOffset("button14");
2205 eval_button15 = PRVM_ED_FindFieldOffset("button15");
2206 eval_button16 = PRVM_ED_FindFieldOffset("button16");
2207 eval_buttonuse = PRVM_ED_FindFieldOffset("buttonuse");
2208 eval_buttonchat = PRVM_ED_FindFieldOffset("buttonchat");
2209 eval_glow_size = PRVM_ED_FindFieldOffset("glow_size");
2210 eval_glow_trail = PRVM_ED_FindFieldOffset("glow_trail");
2211 eval_glow_color = PRVM_ED_FindFieldOffset("glow_color");
2212 eval_items2 = PRVM_ED_FindFieldOffset("items2");
2213 eval_scale = PRVM_ED_FindFieldOffset("scale");
2214 eval_alpha = PRVM_ED_FindFieldOffset("alpha");
2215 eval_renderamt = PRVM_ED_FindFieldOffset("renderamt"); // HalfLife support
2216 eval_rendermode = PRVM_ED_FindFieldOffset("rendermode"); // HalfLife support
2217 eval_fullbright = PRVM_ED_FindFieldOffset("fullbright");
2218 eval_ammo_shells1 = PRVM_ED_FindFieldOffset("ammo_shells1");
2219 eval_ammo_nails1 = PRVM_ED_FindFieldOffset("ammo_nails1");
2220 eval_ammo_lava_nails = PRVM_ED_FindFieldOffset("ammo_lava_nails");
2221 eval_ammo_rockets1 = PRVM_ED_FindFieldOffset("ammo_rockets1");
2222 eval_ammo_multi_rockets = PRVM_ED_FindFieldOffset("ammo_multi_rockets");
2223 eval_ammo_cells1 = PRVM_ED_FindFieldOffset("ammo_cells1");
2224 eval_ammo_plasma = PRVM_ED_FindFieldOffset("ammo_plasma");
2225 eval_idealpitch = PRVM_ED_FindFieldOffset("idealpitch");
2226 eval_pitch_speed = PRVM_ED_FindFieldOffset("pitch_speed");
2227 eval_viewmodelforclient = PRVM_ED_FindFieldOffset("viewmodelforclient");
2228 eval_nodrawtoclient = PRVM_ED_FindFieldOffset("nodrawtoclient");
2229 eval_exteriormodeltoclient = PRVM_ED_FindFieldOffset("exteriormodeltoclient");
2230 eval_drawonlytoclient = PRVM_ED_FindFieldOffset("drawonlytoclient");
2231 eval_ping = PRVM_ED_FindFieldOffset("ping");
2232 eval_movement = PRVM_ED_FindFieldOffset("movement");
2233 eval_pmodel = PRVM_ED_FindFieldOffset("pmodel");
2234 eval_punchvector = PRVM_ED_FindFieldOffset("punchvector");
2235 eval_viewzoom = PRVM_ED_FindFieldOffset("viewzoom");
2236 eval_clientcolors = PRVM_ED_FindFieldOffset("clientcolors");
2237 eval_tag_entity = PRVM_ED_FindFieldOffset("tag_entity");
2238 eval_tag_index = PRVM_ED_FindFieldOffset("tag_index");
2239 eval_light_lev = PRVM_ED_FindFieldOffset("light_lev");
2240 eval_color = PRVM_ED_FindFieldOffset("color");
2241 eval_style = PRVM_ED_FindFieldOffset("style");
2242 eval_pflags = PRVM_ED_FindFieldOffset("pflags");
2243 eval_cursor_active = PRVM_ED_FindFieldOffset("cursor_active");
2244 eval_cursor_screen = PRVM_ED_FindFieldOffset("cursor_screen");
2245 eval_cursor_trace_start = PRVM_ED_FindFieldOffset("cursor_trace_start");
2246 eval_cursor_trace_endpos = PRVM_ED_FindFieldOffset("cursor_trace_endpos");
2247 eval_cursor_trace_ent = PRVM_ED_FindFieldOffset("cursor_trace_ent");
2248 eval_colormod = PRVM_ED_FindFieldOffset("colormod");
2249 eval_playermodel = PRVM_ED_FindFieldOffset("playermodel");
2250 eval_playerskin = PRVM_ED_FindFieldOffset("playerskin");
2251 eval_SendEntity = PRVM_ED_FindFieldOffset("SendEntity");
2252 eval_Version = PRVM_ED_FindFieldOffset("Version");
2253 eval_customizeentityforclient = PRVM_ED_FindFieldOffset("customizeentityforclient");
2254 eval_dphitcontentsmask = PRVM_ED_FindFieldOffset("dphitcontentsmask");
2256 // LordHavoc: allowing QuakeC to override the player movement code
2257 SV_PlayerPhysicsQC = PRVM_ED_FindFunction ("SV_PlayerPhysics");
2258 // LordHavoc: support for endframe
2259 EndFrameQC = PRVM_ED_FindFunction ("EndFrame");
2260 //KrimZon - SERVER COMMANDS IN QUAKEC
2261 SV_ParseClientCommandQC = PRVM_ED_FindFunction ("SV_ParseClientCommand");
2263 //[515]: init stufftext string (it is sent before svc_serverinfo)
2264 if(PRVM_ED_FindGlobal("SV_InitCmd") && PRVM_ED_FindGlobal("SV_InitCmd")->type & ev_string)
2265 SV_InitCmd = PRVM_G_STRING(PRVM_ED_FindGlobal("SV_InitCmd")->ofs);
2269 gval_trace_dpstartcontents = PRVM_ED_FindGlobalOffset("trace_dpstartcontents");
2270 gval_trace_dphitcontents = PRVM_ED_FindGlobalOffset("trace_dphitcontents");
2271 gval_trace_dphitq3surfaceflags = PRVM_ED_FindGlobalOffset("trace_dphitq3surfaceflags");
2272 gval_trace_dphittexturename = PRVM_ED_FindGlobalOffset("trace_dphittexturename");
2275 #define REQFIELDS (sizeof(reqfields) / sizeof(prvm_required_field_t))
2277 prvm_required_field_t reqfields[] =
2279 {ev_entity, "cursor_trace_ent"},
2280 {ev_entity, "drawonlytoclient"},
2281 {ev_entity, "exteriormodeltoclient"},
2282 {ev_entity, "nodrawtoclient"},
2283 {ev_entity, "tag_entity"},
2284 {ev_entity, "viewmodelforclient"},
2285 {ev_float, "alpha"},
2286 {ev_float, "ammo_cells1"},
2287 {ev_float, "ammo_lava_nails"},
2288 {ev_float, "ammo_multi_rockets"},
2289 {ev_float, "ammo_nails1"},
2290 {ev_float, "ammo_plasma"},
2291 {ev_float, "ammo_rockets1"},
2292 {ev_float, "ammo_shells1"},
2293 {ev_float, "button3"},
2294 {ev_float, "button4"},
2295 {ev_float, "button5"},
2296 {ev_float, "button6"},
2297 {ev_float, "button7"},
2298 {ev_float, "button8"},
2299 {ev_float, "button9"},
2300 {ev_float, "button10"},
2301 {ev_float, "button11"},
2302 {ev_float, "button12"},
2303 {ev_float, "button13"},
2304 {ev_float, "button14"},
2305 {ev_float, "button15"},
2306 {ev_float, "button16"},
2307 {ev_float, "buttonchat"},
2308 {ev_float, "buttonuse"},
2309 {ev_float, "clientcolors"},
2310 {ev_float, "cursor_active"},
2311 {ev_float, "fullbright"},
2312 {ev_float, "glow_color"},
2313 {ev_float, "glow_size"},
2314 {ev_float, "glow_trail"},
2315 {ev_float, "gravity"},
2316 {ev_float, "idealpitch"},
2317 {ev_float, "items2"},
2318 {ev_float, "light_lev"},
2319 {ev_float, "pflags"},
2321 {ev_float, "pitch_speed"},
2322 {ev_float, "pmodel"},
2323 {ev_float, "renderamt"}, // HalfLife support
2324 {ev_float, "rendermode"}, // HalfLife support
2325 {ev_float, "scale"},
2326 {ev_float, "style"},
2327 {ev_float, "tag_index"},
2328 {ev_float, "Version"},
2329 {ev_float, "viewzoom"},
2330 {ev_vector, "color"},
2331 {ev_vector, "colormod"},
2332 {ev_vector, "cursor_screen"},
2333 {ev_vector, "cursor_trace_endpos"},
2334 {ev_vector, "cursor_trace_start"},
2335 {ev_vector, "movement"},
2336 {ev_vector, "punchvector"},
2337 {ev_string, "playermodel"},
2338 {ev_string, "playerskin"},
2339 {ev_function, "SendEntity"},
2340 {ev_function, "customizeentityforclient"},
2343 void SV_VM_Setup(void)
2346 PRVM_InitProg( PRVM_SERVERPROG );
2348 // allocate the mempools
2349 prog->progs_mempool = Mem_AllocPool("Server Progs", 0, NULL);
2350 prog->builtins = vm_sv_builtins;
2351 prog->numbuiltins = vm_sv_numbuiltins;
2352 prog->headercrc = PROGHEADER_CRC;
2353 prog->max_edicts = 512;
2354 prog->limit_edicts = MAX_EDICTS;
2355 prog->reserved_edicts = svs.maxclients;
2356 prog->edictprivate_size = sizeof(edict_engineprivate_t);
2357 prog->name = "server";
2358 prog->extensionstring = vm_sv_extensions;
2359 prog->loadintoworld = true;
2361 prog->begin_increase_edicts = SV_VM_CB_BeginIncreaseEdicts;
2362 prog->end_increase_edicts = SV_VM_CB_EndIncreaseEdicts;
2363 prog->init_edict = SV_VM_CB_InitEdict;
2364 prog->free_edict = SV_VM_CB_FreeEdict;
2365 prog->count_edicts = SV_VM_CB_CountEdicts;
2366 prog->load_edict = SV_VM_CB_LoadEdict;
2367 prog->init_cmd = VM_SV_Cmd_Init;
2368 prog->reset_cmd = VM_SV_Cmd_Reset;
2369 prog->error_cmd = Host_Error;
2371 // TODO: add a requiredfuncs list (ask LH if this is necessary at all)
2372 PRVM_LoadProgs( sv_progs.string, 0, NULL, REQFIELDS, reqfields );
2373 SV_VM_FindEdictFieldOffsets();
2375 VM_AutoSentStats_Clear();//[515]: csqc
2376 EntityFrameCSQC_ClearVersions();//[515]: csqc
2381 void SV_VM_Begin(void)
2384 PRVM_SetProg( PRVM_SERVERPROG );
2386 *prog->time = (float) sv.time;
2389 void SV_VM_End(void)