2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 // sv_main.c -- server main program
27 void VM_AutoSentStats_Clear (void);
28 void EntityFrameCSQC_ClearVersions (void);
29 void EntityFrameCSQC_InitClientVersions (int client, qboolean clear);
30 void VM_SV_WriteAutoSentStats (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats);
31 void EntityFrameCSQC_WriteFrame (sizebuf_t *msg, int numstates, const entity_state_t *states);
34 // select which protocol to host, this is fed to Protocol_EnumForName
35 cvar_t sv_protocolname = {0, "sv_protocolname", "DP7", "selects network protocol to host for (values include QUAKE, QUAKEDP, NEHAHRAMOVIE, DP1 and up)"};
36 cvar_t sv_ratelimitlocalplayer = {0, "sv_ratelimitlocalplayer", "0", "whether to apply rate limiting to the local player in a listen server (only useful for testing)"};
37 cvar_t sv_maxrate = {CVAR_SAVE | CVAR_NOTIFY, "sv_maxrate", "10000", "upper limit on client rate cvar, should reflect your network connection quality"};
39 static cvar_t sv_cullentities_pvs = {0, "sv_cullentities_pvs", "1", "fast but loose culling of hidden entities"}; // fast but loose
40 static cvar_t sv_cullentities_trace = {0, "sv_cullentities_trace", "0", "somewhat slow but very tight culling of hidden entities, minimizes network traffic and makes wallhack cheats useless"}; // tends to get false negatives, uses a timeout to keep entities visible a short time after becoming hidden
41 static cvar_t sv_cullentities_stats = {0, "sv_cullentities_stats", "0", "displays stats on network entities culled by various methods for each client"};
42 static cvar_t sv_entpatch = {0, "sv_entpatch", "1", "enables loading of .ent files to override entities in the bsp (for example Threewave CTF server pack contains .ent patch files enabling play of CTF on id1 maps)"};
44 cvar_t sv_gameplayfix_grenadebouncedownslopes = {0, "sv_gameplayfix_grenadebouncedownslopes", "1", "prevents MOVETYPE_BOUNCE (grenades) from getting stuck when fired down a downward sloping surface"};
45 cvar_t sv_gameplayfix_noairborncorpse = {0, "sv_gameplayfix_noairborncorpse", "1", "causes entities (corpses) sitting ontop of moving entities (players) to fall when the moving entity (player) is no longer supporting them"};
46 cvar_t sv_gameplayfix_stepdown = {0, "sv_gameplayfix_stepdown", "0", "attempts to step down stairs, not just up them (prevents the familiar thud..thud..thud.. when running down stairs and slopes)"};
47 cvar_t sv_gameplayfix_stepwhilejumping = {0, "sv_gameplayfix_stepwhilejumping", "1", "applies step-up onto a ledge even while airborn, useful if you would otherwise just-miss the floor when running across small areas with gaps (for instance running across the moving platforms in dm2, or jumping to the megahealth and red armor in dm2 rather than using the bridge)"};
48 cvar_t sv_gameplayfix_swiminbmodels = {0, "sv_gameplayfix_swiminbmodels", "1", "causes pointcontents (used to determine if you are in a liquid) to check bmodel entities as well as the world model, so you can swim around in (possibly moving) water bmodel entities"};
49 cvar_t sv_gameplayfix_setmodelrealbox = {0, "sv_gameplayfix_setmodelrealbox", "1", "fixes a bug in Quake that made setmodel always set the entity box to ('-16 -16 -16', '16 16 16') rather than properly checking the model box, breaks some poorly coded mods"};
50 cvar_t sv_gameplayfix_blowupfallenzombies = {0, "sv_gameplayfix_blowupfallenzombies", "1", "causes findradius to detect SOLID_NOT entities such as zombies and corpses on the floor, allowing splash damage to apply to them"};
51 cvar_t sv_gameplayfix_findradiusdistancetobox = {0, "sv_gameplayfix_findradiusdistancetobox", "1", "causes findradius to check the distance to the corner of a box rather than the center of the box, makes findradius detect bmodels such as very large doors that would otherwise be unaffected by splash damage"};
52 cvar_t sv_gameplayfix_qwplayerphysics = {0, "sv_gameplayfix_qwplayerphysics", "1", "changes water jumping to make it easier to get out of water, and prevents friction on landing when bunnyhopping"};
54 cvar_t sv_progs = {0, "sv_progs", "progs.dat", "selects which quakec progs.dat file to run" };
59 mempool_t *sv_mempool = NULL;
61 //============================================================================
63 extern void SV_Phys_Init (void);
64 extern void SV_World_Init (void);
65 static void SV_SaveEntFile_f(void);
74 Cmd_AddCommand("sv_saveentfile", SV_SaveEntFile_f, "save map entities to .ent file (to allow external editing)");
75 Cvar_RegisterVariable (&sv_maxvelocity);
76 Cvar_RegisterVariable (&sv_gravity);
77 Cvar_RegisterVariable (&sv_friction);
78 Cvar_RegisterVariable (&sv_waterfriction);
79 Cvar_RegisterVariable (&sv_edgefriction);
80 Cvar_RegisterVariable (&sv_stopspeed);
81 Cvar_RegisterVariable (&sv_maxspeed);
82 Cvar_RegisterVariable (&sv_maxairspeed);
83 Cvar_RegisterVariable (&sv_accelerate);
84 Cvar_RegisterVariable (&sv_airaccelerate);
85 Cvar_RegisterVariable (&sv_wateraccelerate);
86 Cvar_RegisterVariable (&sv_idealpitchscale);
87 Cvar_RegisterVariable (&sv_aim);
88 Cvar_RegisterVariable (&sv_nostep);
89 Cvar_RegisterVariable (&sv_cullentities_pvs);
90 Cvar_RegisterVariable (&sv_cullentities_trace);
91 Cvar_RegisterVariable (&sv_cullentities_stats);
92 Cvar_RegisterVariable (&sv_entpatch);
93 Cvar_RegisterVariable (&sv_gameplayfix_grenadebouncedownslopes);
94 Cvar_RegisterVariable (&sv_gameplayfix_noairborncorpse);
95 Cvar_RegisterVariable (&sv_gameplayfix_stepdown);
96 Cvar_RegisterVariable (&sv_gameplayfix_stepwhilejumping);
97 Cvar_RegisterVariable (&sv_gameplayfix_swiminbmodels);
98 Cvar_RegisterVariable (&sv_gameplayfix_setmodelrealbox);
99 Cvar_RegisterVariable (&sv_gameplayfix_blowupfallenzombies);
100 Cvar_RegisterVariable (&sv_gameplayfix_findradiusdistancetobox);
101 Cvar_RegisterVariable (&sv_gameplayfix_qwplayerphysics);
102 Cvar_RegisterVariable (&sv_protocolname);
103 Cvar_RegisterVariable (&sv_ratelimitlocalplayer);
104 Cvar_RegisterVariable (&sv_maxrate);
105 Cvar_RegisterVariable (&sv_progs);
111 sv_mempool = Mem_AllocPool("server", 0, NULL);
114 static void SV_SaveEntFile_f(void)
116 char basename[MAX_QPATH];
117 if (!sv.active || !sv.worldmodel)
119 Con_Print("Not running a server\n");
122 FS_StripExtension(sv.worldmodel->name, basename, sizeof(basename));
123 FS_WriteFile(va("%s.ent", basename), sv.worldmodel->brush.entities, (fs_offset_t)strlen(sv.worldmodel->brush.entities));
128 =============================================================================
132 =============================================================================
139 Make sure the event gets sent to all clients
142 void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count)
146 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-18)
148 MSG_WriteByte (&sv.datagram, svc_particle);
149 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
150 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
151 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
152 for (i=0 ; i<3 ; i++)
153 MSG_WriteChar (&sv.datagram, (int)bound(-128, dir[i]*16, 127));
154 MSG_WriteByte (&sv.datagram, count);
155 MSG_WriteByte (&sv.datagram, color);
162 Make sure the event gets sent to all clients
165 void SV_StartEffect (vec3_t org, int modelindex, int startframe, int framecount, int framerate)
167 if (modelindex >= 256 || startframe >= 256)
169 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-19)
171 MSG_WriteByte (&sv.datagram, svc_effect2);
172 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
173 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
174 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
175 MSG_WriteShort (&sv.datagram, modelindex);
176 MSG_WriteShort (&sv.datagram, startframe);
177 MSG_WriteByte (&sv.datagram, framecount);
178 MSG_WriteByte (&sv.datagram, framerate);
182 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-17)
184 MSG_WriteByte (&sv.datagram, svc_effect);
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_WriteByte (&sv.datagram, modelindex);
189 MSG_WriteByte (&sv.datagram, startframe);
190 MSG_WriteByte (&sv.datagram, framecount);
191 MSG_WriteByte (&sv.datagram, framerate);
199 Each entity can have eight independant sound sources, like voice,
202 Channel 0 is an auto-allocate channel, the others override anything
203 already running on that entity/channel pair.
205 An attenuation of 0 will play full volume everywhere in the level.
206 Larger attenuations will drop off. (max 4 attenuation)
210 void SV_StartSound (prvm_edict_t *entity, int channel, const char *sample, int volume, float attenuation)
212 int sound_num, field_mask, i, ent;
214 if (volume < 0 || volume > 255)
216 Con_Printf ("SV_StartSound: volume = %i\n", volume);
220 if (attenuation < 0 || attenuation > 4)
222 Con_Printf ("SV_StartSound: attenuation = %f\n", attenuation);
226 if (channel < 0 || channel > 7)
228 Con_Printf ("SV_StartSound: channel = %i\n", channel);
232 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-21)
235 // find precache number for sound
236 sound_num = SV_SoundIndex(sample, 1);
240 ent = PRVM_NUM_FOR_EDICT(entity);
243 if (volume != DEFAULT_SOUND_PACKET_VOLUME)
244 field_mask |= SND_VOLUME;
245 if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
246 field_mask |= SND_ATTENUATION;
248 field_mask |= SND_LARGEENTITY;
249 if (sound_num >= 256 || channel >= 8)
250 field_mask |= SND_LARGESOUND;
252 // directed messages go only to the entity they are targeted on
253 MSG_WriteByte (&sv.datagram, svc_sound);
254 MSG_WriteByte (&sv.datagram, field_mask);
255 if (field_mask & SND_VOLUME)
256 MSG_WriteByte (&sv.datagram, volume);
257 if (field_mask & SND_ATTENUATION)
258 MSG_WriteByte (&sv.datagram, (int)(attenuation*64));
259 if (field_mask & SND_LARGEENTITY)
261 MSG_WriteShort (&sv.datagram, ent);
262 MSG_WriteByte (&sv.datagram, channel);
265 MSG_WriteShort (&sv.datagram, (ent<<3) | channel);
266 if (field_mask & SND_LARGESOUND)
267 MSG_WriteShort (&sv.datagram, sound_num);
269 MSG_WriteByte (&sv.datagram, sound_num);
270 for (i = 0;i < 3;i++)
271 MSG_WriteCoord (&sv.datagram, entity->fields.server->origin[i]+0.5*(entity->fields.server->mins[i]+entity->fields.server->maxs[i]), sv.protocol);
275 ==============================================================================
279 ==============================================================================
282 static const char *SV_InitCmd; //[515]: svprogs able to send cmd to client on connect
283 extern qboolean csqc_loaded;
288 Sends the first message from the server to a connected client.
289 This will be sent on the initial connection and upon each server load.
292 void SV_SendServerinfo (client_t *client)
297 // we know that this client has a netconnection and thus is not a bot
299 // edicts get reallocated on level changes, so we need to update it here
300 client->edict = PRVM_EDICT_NUM((client - svs.clients) + 1);
302 // clear cached stuff that depends on the level
303 client->weaponmodel[0] = 0;
304 client->weaponmodelindex = 0;
306 // LordHavoc: clear entityframe tracking
307 client->latestframenum = 0;
309 if (client->entitydatabase)
310 EntityFrame_FreeDatabase(client->entitydatabase);
311 if (client->entitydatabase4)
312 EntityFrame4_FreeDatabase(client->entitydatabase4);
313 if (client->entitydatabase5)
314 EntityFrame5_FreeDatabase(client->entitydatabase5);
316 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
318 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3)
319 client->entitydatabase = EntityFrame_AllocDatabase(sv_mempool);
320 else if (sv.protocol == PROTOCOL_DARKPLACES4)
321 client->entitydatabase4 = EntityFrame4_AllocDatabase(sv_mempool);
323 client->entitydatabase5 = EntityFrame5_AllocDatabase(sv_mempool);
326 SZ_Clear (&client->netconnection->message);
327 MSG_WriteByte (&client->netconnection->message, svc_print);
328 dpsnprintf (message, sizeof (message), "\nServer: %s build %s (progs %i crc)", gamename, buildstring, prog->filecrc);
329 MSG_WriteString (&client->netconnection->message,message);
331 // FIXME: LordHavoc: this does not work on dedicated servers, needs fixing.
332 //[515]: init csprogs according to version of svprogs, check the crc, etc.
333 if(csqc_loaded && (cls.state == ca_dedicated || PRVM_NUM_FOR_EDICT(client->edict) != 1))
335 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
337 MSG_WriteString (&client->netconnection->message, va("csqc_progcrc %i;%s\n", csqc_progcrc.integer, SV_InitCmd));
339 MSG_WriteString (&client->netconnection->message, va("csqc_progcrc %i\n", csqc_progcrc.integer));
342 MSG_WriteByte (&client->netconnection->message, svc_serverinfo);
343 MSG_WriteLong (&client->netconnection->message, Protocol_NumberForEnum(sv.protocol));
344 MSG_WriteByte (&client->netconnection->message, svs.maxclients);
346 if (!coop.integer && deathmatch.integer)
347 MSG_WriteByte (&client->netconnection->message, GAME_DEATHMATCH);
349 MSG_WriteByte (&client->netconnection->message, GAME_COOP);
351 MSG_WriteString (&client->netconnection->message,PRVM_GetString(prog->edicts->fields.server->message));
353 for (i = 1;i < MAX_MODELS && sv.model_precache[i][0];i++)
354 MSG_WriteString (&client->netconnection->message, sv.model_precache[i]);
355 MSG_WriteByte (&client->netconnection->message, 0);
357 for (i = 1;i < MAX_SOUNDS && sv.sound_precache[i][0];i++)
358 MSG_WriteString (&client->netconnection->message, sv.sound_precache[i]);
359 MSG_WriteByte (&client->netconnection->message, 0);
362 MSG_WriteByte (&client->netconnection->message, svc_cdtrack);
363 MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
364 MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
367 MSG_WriteByte (&client->netconnection->message, svc_setview);
368 MSG_WriteShort (&client->netconnection->message, PRVM_NUM_FOR_EDICT(client->edict));
370 MSG_WriteByte (&client->netconnection->message, svc_signonnum);
371 MSG_WriteByte (&client->netconnection->message, 1);
373 client->spawned = false; // need prespawn, spawn, etc
380 Initializes a client_t for a new net connection. This will only be called
381 once for a player each game, not once for each level change.
384 void SV_ConnectClient (int clientnum, netconn_t *netconnection)
388 float spawn_parms[NUM_SPAWN_PARMS];
390 client = svs.clients + clientnum;
392 if(netconnection)//[515]: bots don't play with csqc =)
393 EntityFrameCSQC_InitClientVersions(clientnum, false);
395 // set up the client_t
397 memcpy (spawn_parms, client->spawn_parms, sizeof(spawn_parms));
398 memset (client, 0, sizeof(*client));
399 client->active = true;
400 client->netconnection = netconnection;
402 Con_DPrintf("Client %s connected\n", client->netconnection ? client->netconnection->address : "botclient");
404 strcpy(client->name, "unconnected");
405 strcpy(client->old_name, "unconnected");
406 client->spawned = false;
407 client->edict = PRVM_EDICT_NUM(clientnum+1);
408 if (client->netconnection)
409 client->netconnection->message.allowoverflow = true; // we can catch it
410 // updated by receiving "rate" command from client
411 client->rate = NET_MINRATE;
412 // no limits for local player
413 if (client->netconnection && LHNETADDRESS_GetAddressType(&client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP)
414 client->rate = 1000000000;
415 client->connecttime = realtime;
418 memcpy (client->spawn_parms, spawn_parms, sizeof(spawn_parms));
421 // call the progs to get default spawn parms for the new client
422 // set self to world to intentionally cause errors with broken SetNewParms code in some mods
423 prog->globals.server->self = 0;
424 PRVM_ExecuteProgram (prog->globals.server->SetNewParms, "QC function SetNewParms is missing");
425 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
426 client->spawn_parms[i] = (&prog->globals.server->parm1)[i];
428 // set up the entity for this client (including .colormap, .team, etc)
429 PRVM_ED_ClearEdict(client->edict);
432 // don't call SendServerinfo for a fresh botclient because its fields have
433 // not been set up by the qc yet
434 if (client->netconnection)
435 SV_SendServerinfo (client);
437 client->spawned = true;
442 ===============================================================================
446 ===============================================================================
455 void SV_ClearDatagram (void)
457 SZ_Clear (&sv.datagram);
461 =============================================================================
463 The PVS must include a small area around the client to allow head bobbing
464 or other small motion on the client side. Otherwise, a bob might cause an
465 entity that should be visible to not show up, especially when the bob
468 =============================================================================
471 int sv_writeentitiestoclient_pvsbytes;
472 unsigned char sv_writeentitiestoclient_pvs[MAX_MAP_LEAFS/8];
474 static int numsendentities;
475 static entity_state_t sendentities[MAX_EDICTS];
476 static entity_state_t *sendentitiesindex[MAX_EDICTS];
478 qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *cs, int e)
481 unsigned int modelindex, effects, flags, glowsize, lightstyle, lightpflags, light[4], specialvisibilityradius;
482 unsigned int customizeentityforclient;
484 vec3_t cullmins, cullmaxs;
488 // EF_NODRAW prevents sending for any reason except for your own
489 // client, so we must keep all clients in this superset
490 effects = (unsigned)ent->fields.server->effects;
492 // we can omit invisible entities with no effects that are not clients
493 // LordHavoc: this could kill tags attached to an invisible entity, I
494 // just hope we never have to support that case
495 i = (int)ent->fields.server->modelindex;
496 modelindex = (i >= 1 && i < MAX_MODELS && *PRVM_GetString(ent->fields.server->model)) ? i : 0;
499 i = (int)(PRVM_GETEDICTFIELDVALUE(ent, eval_glow_size)->_float * 0.25f);
500 glowsize = (unsigned char)bound(0, i, 255);
501 if (PRVM_GETEDICTFIELDVALUE(ent, eval_glow_trail)->_float)
502 flags |= RENDER_GLOWTRAIL;
504 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[0]*256;
505 light[0] = (unsigned short)bound(0, f, 65535);
506 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[1]*256;
507 light[1] = (unsigned short)bound(0, f, 65535);
508 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[2]*256;
509 light[2] = (unsigned short)bound(0, f, 65535);
510 f = PRVM_GETEDICTFIELDVALUE(ent, eval_light_lev)->_float;
511 light[3] = (unsigned short)bound(0, f, 65535);
512 lightstyle = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_style)->_float;
513 lightpflags = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_pflags)->_float;
515 if (gamemode == GAME_TENEBRAE)
517 // tenebrae's EF_FULLDYNAMIC conflicts with Q2's EF_NODRAW
521 lightpflags |= PFLAGS_FULLDYNAMIC;
523 // tenebrae's EF_GREEN conflicts with DP's EF_ADDITIVE
527 light[0] = (int)(0.2*256);
528 light[1] = (int)(1.0*256);
529 light[2] = (int)(0.2*256);
531 lightpflags |= PFLAGS_FULLDYNAMIC;
535 specialvisibilityradius = 0;
536 if (lightpflags & PFLAGS_FULLDYNAMIC)
537 specialvisibilityradius = max(specialvisibilityradius, light[3]);
539 specialvisibilityradius = max(specialvisibilityradius, glowsize * 4);
540 if (flags & RENDER_GLOWTRAIL)
541 specialvisibilityradius = max(specialvisibilityradius, 100);
542 if (effects & (EF_BRIGHTFIELD | EF_MUZZLEFLASH | EF_BRIGHTLIGHT | EF_DIMLIGHT | EF_RED | EF_BLUE | EF_FLAME | EF_STARDUST))
544 if (effects & EF_BRIGHTFIELD)
545 specialvisibilityradius = max(specialvisibilityradius, 80);
546 if (effects & EF_MUZZLEFLASH)
547 specialvisibilityradius = max(specialvisibilityradius, 100);
548 if (effects & EF_BRIGHTLIGHT)
549 specialvisibilityradius = max(specialvisibilityradius, 400);
550 if (effects & EF_DIMLIGHT)
551 specialvisibilityradius = max(specialvisibilityradius, 200);
552 if (effects & EF_RED)
553 specialvisibilityradius = max(specialvisibilityradius, 200);
554 if (effects & EF_BLUE)
555 specialvisibilityradius = max(specialvisibilityradius, 200);
556 if (effects & EF_FLAME)
557 specialvisibilityradius = max(specialvisibilityradius, 250);
558 if (effects & EF_STARDUST)
559 specialvisibilityradius = max(specialvisibilityradius, 100);
562 // early culling checks
563 // (final culling is done by SV_MarkWriteEntityStateToClient)
564 customizeentityforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_customizeentityforclient)->function;
565 if (!customizeentityforclient)
567 if (e > svs.maxclients && (!modelindex && !specialvisibilityradius))
569 // this 2 billion unit check is actually to detect NAN origins
570 // (we really don't want to send those)
571 if (VectorLength2(ent->fields.server->origin) > 2000000000.0*2000000000.0)
579 VectorCopy(ent->fields.server->origin, cs->origin);
580 VectorCopy(ent->fields.server->angles, cs->angles);
582 cs->effects = effects;
583 cs->colormap = (unsigned)ent->fields.server->colormap;
584 cs->modelindex = modelindex;
585 cs->skin = (unsigned)ent->fields.server->skin;
586 cs->frame = (unsigned)ent->fields.server->frame;
587 cs->viewmodelforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)->edict;
588 cs->exteriormodelforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_exteriormodeltoclient)->edict;
589 cs->nodrawtoclient = PRVM_GETEDICTFIELDVALUE(ent, eval_nodrawtoclient)->edict;
590 cs->drawonlytoclient = PRVM_GETEDICTFIELDVALUE(ent, eval_drawonlytoclient)->edict;
591 cs->customizeentityforclient = customizeentityforclient;
592 cs->tagentity = PRVM_GETEDICTFIELDVALUE(ent, eval_tag_entity)->edict;
593 cs->tagindex = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_tag_index)->_float;
594 cs->glowsize = glowsize;
596 // don't need to init cs->colormod because the defaultstate did that for us
597 //cs->colormod[0] = cs->colormod[1] = cs->colormod[2] = 32;
598 val = PRVM_GETEDICTFIELDVALUE(ent, eval_colormod);
599 if (val->vector[0] || val->vector[1] || val->vector[2])
601 i = (int)(val->vector[0] * 32.0f);cs->colormod[0] = bound(0, i, 255);
602 i = (int)(val->vector[1] * 32.0f);cs->colormod[1] = bound(0, i, 255);
603 i = (int)(val->vector[2] * 32.0f);cs->colormod[2] = bound(0, i, 255);
606 cs->modelindex = modelindex;
609 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_alpha)->_float * 255.0f);
613 cs->alpha = (unsigned char)bound(0, i, 255);
616 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_renderamt)->_float);
620 cs->alpha = (unsigned char)bound(0, i, 255);
624 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_scale)->_float * 16.0f);
628 cs->scale = (unsigned char)bound(0, i, 255);
632 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_glow_color)->_float);
634 cs->glowcolor = (int)f;
636 if (PRVM_GETEDICTFIELDVALUE(ent, eval_fullbright)->_float)
637 cs->effects |= EF_FULLBRIGHT;
639 if (ent->fields.server->movetype == MOVETYPE_STEP)
640 cs->flags |= RENDER_STEP;
641 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)
642 cs->flags |= RENDER_LOWPRECISION;
643 if (ent->fields.server->colormap >= 1024)
644 cs->flags |= RENDER_COLORMAPPED;
645 if (cs->viewmodelforclient)
646 cs->flags |= RENDER_VIEWMODEL; // show relative to the view
648 cs->light[0] = light[0];
649 cs->light[1] = light[1];
650 cs->light[2] = light[2];
651 cs->light[3] = light[3];
652 cs->lightstyle = lightstyle;
653 cs->lightpflags = lightpflags;
655 cs->specialvisibilityradius = specialvisibilityradius;
657 // calculate the visible box of this entity (don't use the physics box
658 // as that is often smaller than a model, and would not count
659 // specialvisibilityradius)
660 if ((model = sv.models[modelindex]))
662 float scale = cs->scale * (1.0f / 16.0f);
663 if (cs->angles[0] || cs->angles[2]) // pitch and roll
665 VectorMA(cs->origin, scale, model->rotatedmins, cullmins);
666 VectorMA(cs->origin, scale, model->rotatedmaxs, cullmaxs);
668 else if (cs->angles[1])
670 VectorMA(cs->origin, scale, model->yawmins, cullmins);
671 VectorMA(cs->origin, scale, model->yawmaxs, cullmaxs);
675 VectorMA(cs->origin, scale, model->normalmins, cullmins);
676 VectorMA(cs->origin, scale, model->normalmaxs, cullmaxs);
681 // if there is no model (or it could not be loaded), use the physics box
682 VectorAdd(cs->origin, ent->fields.server->mins, cullmins);
683 VectorAdd(cs->origin, ent->fields.server->maxs, cullmaxs);
685 if (specialvisibilityradius)
687 cullmins[0] = min(cullmins[0], cs->origin[0] - specialvisibilityradius);
688 cullmins[1] = min(cullmins[1], cs->origin[1] - specialvisibilityradius);
689 cullmins[2] = min(cullmins[2], cs->origin[2] - specialvisibilityradius);
690 cullmaxs[0] = max(cullmaxs[0], cs->origin[0] + specialvisibilityradius);
691 cullmaxs[1] = max(cullmaxs[1], cs->origin[1] + specialvisibilityradius);
692 cullmaxs[2] = max(cullmaxs[2], cs->origin[2] + specialvisibilityradius);
694 if (!VectorCompare(cullmins, ent->priv.server->cullmins) || !VectorCompare(cullmaxs, ent->priv.server->cullmaxs))
696 VectorCopy(cullmins, ent->priv.server->cullmins);
697 VectorCopy(cullmaxs, ent->priv.server->cullmaxs);
698 ent->priv.server->pvs_numclusters = -1;
699 if (sv.worldmodel && sv.worldmodel->brush.FindBoxClusters)
701 i = sv.worldmodel->brush.FindBoxClusters(sv.worldmodel, cullmins, cullmaxs, MAX_ENTITYCLUSTERS, ent->priv.server->pvs_clusterlist);
702 if (i <= MAX_ENTITYCLUSTERS)
703 ent->priv.server->pvs_numclusters = i;
710 void SV_PrepareEntitiesForSending(void)
714 // send all entities that touch the pvs
716 sendentitiesindex[0] = NULL;
717 memset(sendentitiesindex, 0, prog->num_edicts * sizeof(entity_state_t *));
718 for (e = 1, ent = PRVM_NEXT_EDICT(prog->edicts);e < prog->num_edicts;e++, ent = PRVM_NEXT_EDICT(ent))
720 if (!ent->priv.server->free && SV_PrepareEntityForSending(ent, sendentities + numsendentities, e))
722 sendentitiesindex[e] = sendentities + numsendentities;
728 static int sententitiesmark = 0;
729 static int sententities[MAX_EDICTS];
730 static int sententitiesconsideration[MAX_EDICTS];
731 static int sv_writeentitiestoclient_culled_pvs;
732 static int sv_writeentitiestoclient_culled_trace;
733 static int sv_writeentitiestoclient_visibleentities;
734 static int sv_writeentitiestoclient_totalentities;
735 //static entity_frame_t sv_writeentitiestoclient_entityframe;
736 static int sv_writeentitiestoclient_clentnum;
737 static vec3_t sv_writeentitiestoclient_testeye;
738 static client_t *sv_writeentitiestoclient_client;
740 void SV_MarkWriteEntityStateToClient(entity_state_t *s)
747 if (sententitiesconsideration[s->number] == sententitiesmark)
749 sententitiesconsideration[s->number] = sententitiesmark;
750 sv_writeentitiestoclient_totalentities++;
752 if (s->customizeentityforclient)
754 prog->globals.server->self = s->number;
755 prog->globals.server->other = sv_writeentitiestoclient_clentnum;
756 PRVM_ExecuteProgram(s->customizeentityforclient, "customizeentityforclient: NULL function");
757 if(!PRVM_G_FLOAT(OFS_RETURN) || !SV_PrepareEntityForSending(PRVM_EDICT_NUM(s->number), s, s->number))
761 // never reject player
762 if (s->number != sv_writeentitiestoclient_clentnum)
764 // check various rejection conditions
765 if (s->nodrawtoclient == sv_writeentitiestoclient_clentnum)
767 if (s->drawonlytoclient && s->drawonlytoclient != sv_writeentitiestoclient_clentnum)
769 if (s->effects & EF_NODRAW)
771 // LordHavoc: only send entities with a model or important effects
772 if (!s->modelindex && s->specialvisibilityradius == 0)
775 // viewmodels don't have visibility checking
776 if (s->viewmodelforclient)
778 if (s->viewmodelforclient != sv_writeentitiestoclient_clentnum)
781 else if (s->tagentity)
783 // tag attached entities simply check their parent
784 if (!sendentitiesindex[s->tagentity])
786 SV_MarkWriteEntityStateToClient(sendentitiesindex[s->tagentity]);
787 if (sententities[s->tagentity] != sententitiesmark)
790 // always send world submodels in newer protocols because they don't
791 // generate much traffic (in old protocols they hog bandwidth)
792 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)))
794 // entity has survived every check so far, check if visible
795 ed = PRVM_EDICT_NUM(s->number);
797 // if not touching a visible leaf
798 if (sv_cullentities_pvs.integer && sv_writeentitiestoclient_pvsbytes)
800 if (ed->priv.server->pvs_numclusters < 0)
802 // entity too big for clusters list
803 if (sv.worldmodel && sv.worldmodel->brush.BoxTouchingPVS && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, sv_writeentitiestoclient_pvs, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
805 sv_writeentitiestoclient_culled_pvs++;
812 // check cached clusters list
813 for (i = 0;i < ed->priv.server->pvs_numclusters;i++)
814 if (CHECKPVSBIT(sv_writeentitiestoclient_pvs, ed->priv.server->pvs_clusterlist[i]))
816 if (i == ed->priv.server->pvs_numclusters)
818 sv_writeentitiestoclient_culled_pvs++;
824 // or not seen by random tracelines
825 if (sv_cullentities_trace.integer && !isbmodel)
827 // LordHavoc: test center first
828 testorigin[0] = (ed->priv.server->cullmins[0] + ed->priv.server->cullmaxs[0]) * 0.5f;
829 testorigin[1] = (ed->priv.server->cullmins[1] + ed->priv.server->cullmaxs[1]) * 0.5f;
830 testorigin[2] = (ed->priv.server->cullmins[2] + ed->priv.server->cullmaxs[2]) * 0.5f;
831 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
832 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
833 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
836 // LordHavoc: test random offsets, to maximize chance of detection
837 testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]);
838 testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]);
839 testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]);
840 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
841 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
842 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
845 if (s->specialvisibilityradius)
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;
857 if (realtime > sv_writeentitiestoclient_client->visibletime[s->number])
859 sv_writeentitiestoclient_culled_trace++;
866 // this just marks it for sending
867 // FIXME: it would be more efficient to send here, but the entity
868 // compressor isn't that flexible
869 sv_writeentitiestoclient_visibleentities++;
870 sententities[s->number] = sententitiesmark;
873 entity_state_t sendstates[MAX_EDICTS];
874 extern int csqc_clent;
876 void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t *msg, int *stats)
878 int i, numsendstates;
881 // if there isn't enough space to accomplish anything, skip it
882 if (msg->cursize + 25 > msg->maxsize)
885 sv_writeentitiestoclient_client = client;
887 sv_writeentitiestoclient_culled_pvs = 0;
888 sv_writeentitiestoclient_culled_trace = 0;
889 sv_writeentitiestoclient_visibleentities = 0;
890 sv_writeentitiestoclient_totalentities = 0;
892 // find the client's PVS
893 // the real place being tested from
894 VectorAdd(clent->fields.server->origin, clent->fields.server->view_ofs, sv_writeentitiestoclient_testeye);
895 sv_writeentitiestoclient_pvsbytes = 0;
896 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
897 sv_writeentitiestoclient_pvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, sv_writeentitiestoclient_testeye, 8, sv_writeentitiestoclient_pvs, sizeof(sv_writeentitiestoclient_pvs));
899 csqc_clent = sv_writeentitiestoclient_clentnum = PRVM_EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes
903 for (i = 0;i < numsendentities;i++)
904 SV_MarkWriteEntityStateToClient(sendentities + i);
907 for (i = 0;i < numsendentities;i++)
909 if (sententities[sendentities[i].number] == sententitiesmark)
911 s = &sendstates[numsendstates++];
912 *s = sendentities[i];
913 if (s->exteriormodelforclient && s->exteriormodelforclient == sv_writeentitiestoclient_clentnum)
914 s->flags |= RENDER_EXTERIORMODEL;
918 if (sv_cullentities_stats.integer)
919 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);
921 EntityFrameCSQC_WriteFrame(msg, numsendstates, sendstates);
923 if (client->entitydatabase5)
924 EntityFrame5_WriteFrame(msg, client->entitydatabase5, numsendstates, sendstates, client - svs.clients + 1, stats, client->movesequence);
925 else if (client->entitydatabase4)
926 EntityFrame4_WriteFrame(msg, client->entitydatabase4, numsendstates, sendstates);
927 else if (client->entitydatabase)
928 EntityFrame_WriteFrame(msg, client->entitydatabase, numsendstates, sendstates, client - svs.clients + 1);
930 EntityFrameQuake_WriteFrame(msg, numsendstates, sendstates);
939 void SV_CleanupEnts (void)
944 ent = PRVM_NEXT_EDICT(prog->edicts);
945 for (e=1 ; e<prog->num_edicts ; e++, ent = PRVM_NEXT_EDICT(ent))
946 ent->fields.server->effects = (int)ent->fields.server->effects & ~EF_MUZZLEFLASH;
951 SV_WriteClientdataToMessage
955 void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
967 // send a damage message
969 if (ent->fields.server->dmg_take || ent->fields.server->dmg_save)
971 other = PRVM_PROG_TO_EDICT(ent->fields.server->dmg_inflictor);
972 MSG_WriteByte (msg, svc_damage);
973 MSG_WriteByte (msg, (int)ent->fields.server->dmg_save);
974 MSG_WriteByte (msg, (int)ent->fields.server->dmg_take);
975 for (i=0 ; i<3 ; i++)
976 MSG_WriteCoord (msg, other->fields.server->origin[i] + 0.5*(other->fields.server->mins[i] + other->fields.server->maxs[i]), sv.protocol);
978 ent->fields.server->dmg_take = 0;
979 ent->fields.server->dmg_save = 0;
983 // send the current viewpos offset from the view entity
985 SV_SetIdealPitch (); // how much to look up / down ideally
987 // a fixangle might get lost in a dropped packet. Oh well.
988 if ( ent->fields.server->fixangle )
990 MSG_WriteByte (msg, svc_setangle);
991 for (i=0 ; i < 3 ; i++)
992 MSG_WriteAngle (msg, ent->fields.server->angles[i], sv.protocol);
993 ent->fields.server->fixangle = 0;
996 // stuff the sigil bits into the high bits of items for sbar, or else
998 val = PRVM_GETEDICTFIELDVALUE(ent, eval_items2);
999 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
1000 items = (int)ent->fields.server->items | ((int)val->_float << 23);
1002 items = (int)ent->fields.server->items | ((int)prog->globals.server->serverflags << 28);
1004 VectorClear(punchvector);
1005 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_punchvector)))
1006 VectorCopy(val->vector, punchvector);
1008 // cache weapon model name and index in client struct to save time
1009 // (this search can be almost 1% of cpu time!)
1010 s = PRVM_GetString(ent->fields.server->weaponmodel);
1011 if (strcmp(s, client->weaponmodel))
1013 strlcpy(client->weaponmodel, s, sizeof(client->weaponmodel));
1014 client->weaponmodelindex = SV_ModelIndex(s, 1);
1018 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_viewzoom)))
1019 viewzoom = (int)(val->_float * 255.0f);
1025 if ((int)ent->fields.server->flags & FL_ONGROUND)
1026 bits |= SU_ONGROUND;
1027 if (ent->fields.server->waterlevel >= 2)
1029 if (ent->fields.server->idealpitch)
1030 bits |= SU_IDEALPITCH;
1032 for (i=0 ; i<3 ; i++)
1034 if (ent->fields.server->punchangle[i])
1035 bits |= (SU_PUNCH1<<i);
1036 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
1038 bits |= (SU_PUNCHVEC1<<i);
1039 if (ent->fields.server->velocity[i])
1040 bits |= (SU_VELOCITY1<<i);
1043 memset(stats, 0, sizeof(int[MAX_CL_STATS]));
1044 stats[STAT_VIEWHEIGHT] = (int)ent->fields.server->view_ofs[2];
1045 stats[STAT_ITEMS] = items;
1046 stats[STAT_WEAPONFRAME] = (int)ent->fields.server->weaponframe;
1047 stats[STAT_ARMOR] = (int)ent->fields.server->armorvalue;
1048 stats[STAT_WEAPON] = client->weaponmodelindex;
1049 stats[STAT_HEALTH] = (int)ent->fields.server->health;
1050 stats[STAT_AMMO] = (int)ent->fields.server->currentammo;
1051 stats[STAT_SHELLS] = (int)ent->fields.server->ammo_shells;
1052 stats[STAT_NAILS] = (int)ent->fields.server->ammo_nails;
1053 stats[STAT_ROCKETS] = (int)ent->fields.server->ammo_rockets;
1054 stats[STAT_CELLS] = (int)ent->fields.server->ammo_cells;
1055 stats[STAT_ACTIVEWEAPON] = (int)ent->fields.server->weapon;
1056 stats[STAT_VIEWZOOM] = viewzoom;
1057 // the QC bumps these itself by sending svc_'s, so we have to keep them
1058 // zero or they'll be corrected by the engine
1059 //stats[STAT_TOTALSECRETS] = prog->globals.server->total_secrets;
1060 //stats[STAT_TOTALMONSTERS] = prog->globals.server->total_monsters;
1061 //stats[STAT_SECRETS] = prog->globals.server->found_secrets;
1062 //stats[STAT_MONSTERS] = prog->globals.server->killed_monsters;
1064 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)
1066 if (stats[STAT_VIEWHEIGHT] != DEFAULT_VIEWHEIGHT) bits |= SU_VIEWHEIGHT;
1068 if (stats[STAT_WEAPONFRAME]) bits |= SU_WEAPONFRAME;
1069 if (stats[STAT_ARMOR]) bits |= SU_ARMOR;
1071 // FIXME: which protocols support this? does PROTOCOL_DARKPLACES3 support viewzoom?
1072 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
1073 if (viewzoom != 255)
1074 bits |= SU_VIEWZOOM;
1079 if (bits >= 16777216)
1083 MSG_WriteByte (msg, svc_clientdata);
1084 MSG_WriteShort (msg, bits);
1085 if (bits & SU_EXTEND1)
1086 MSG_WriteByte(msg, bits >> 16);
1087 if (bits & SU_EXTEND2)
1088 MSG_WriteByte(msg, bits >> 24);
1090 if (bits & SU_VIEWHEIGHT)
1091 MSG_WriteChar (msg, stats[STAT_VIEWHEIGHT]);
1093 if (bits & SU_IDEALPITCH)
1094 MSG_WriteChar (msg, (int)ent->fields.server->idealpitch);
1096 for (i=0 ; i<3 ; i++)
1098 if (bits & (SU_PUNCH1<<i))
1100 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1101 MSG_WriteChar(msg, (int)ent->fields.server->punchangle[i]);
1103 MSG_WriteAngle16i(msg, ent->fields.server->punchangle[i]);
1105 if (bits & (SU_PUNCHVEC1<<i))
1107 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1108 MSG_WriteCoord16i(msg, punchvector[i]);
1110 MSG_WriteCoord32f(msg, punchvector[i]);
1112 if (bits & (SU_VELOCITY1<<i))
1114 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1115 MSG_WriteChar(msg, (int)(ent->fields.server->velocity[i] * (1.0f / 16.0f)));
1117 MSG_WriteCoord32f(msg, ent->fields.server->velocity[i]);
1121 if (bits & SU_ITEMS)
1122 MSG_WriteLong (msg, stats[STAT_ITEMS]);
1124 if (sv.protocol == PROTOCOL_DARKPLACES5)
1126 if (bits & SU_WEAPONFRAME)
1127 MSG_WriteShort (msg, stats[STAT_WEAPONFRAME]);
1128 if (bits & SU_ARMOR)
1129 MSG_WriteShort (msg, stats[STAT_ARMOR]);
1130 if (bits & SU_WEAPON)
1131 MSG_WriteShort (msg, stats[STAT_WEAPON]);
1132 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1133 MSG_WriteShort (msg, stats[STAT_AMMO]);
1134 MSG_WriteShort (msg, stats[STAT_SHELLS]);
1135 MSG_WriteShort (msg, stats[STAT_NAILS]);
1136 MSG_WriteShort (msg, stats[STAT_ROCKETS]);
1137 MSG_WriteShort (msg, stats[STAT_CELLS]);
1138 MSG_WriteShort (msg, stats[STAT_ACTIVEWEAPON]);
1139 if (bits & SU_VIEWZOOM)
1140 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1142 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)
1144 if (bits & SU_WEAPONFRAME)
1145 MSG_WriteByte (msg, stats[STAT_WEAPONFRAME]);
1146 if (bits & SU_ARMOR)
1147 MSG_WriteByte (msg, stats[STAT_ARMOR]);
1148 if (bits & SU_WEAPON)
1149 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1150 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1151 MSG_WriteByte (msg, stats[STAT_AMMO]);
1152 MSG_WriteByte (msg, stats[STAT_SHELLS]);
1153 MSG_WriteByte (msg, stats[STAT_NAILS]);
1154 MSG_WriteByte (msg, stats[STAT_ROCKETS]);
1155 MSG_WriteByte (msg, stats[STAT_CELLS]);
1156 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_NEXUIZ)
1158 for (i = 0;i < 32;i++)
1159 if (stats[STAT_WEAPON] & (1<<i))
1161 MSG_WriteByte (msg, i);
1164 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1165 if (bits & SU_VIEWZOOM)
1167 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1168 MSG_WriteByte (msg, bound(0, stats[STAT_VIEWZOOM], 255));
1170 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1176 =======================
1177 SV_SendClientDatagram
1178 =======================
1180 static unsigned char sv_sendclientdatagram_buf[NET_MAXMESSAGE]; // FIXME?
1181 void SV_SendClientDatagram (client_t *client)
1183 int rate, maxrate, maxsize, maxsize2;
1185 int stats[MAX_CL_STATS];
1187 if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP && !sv_ratelimitlocalplayer.integer)
1189 // for good singleplayer, send huge packets
1190 maxsize = sizeof(sv_sendclientdatagram_buf);
1191 maxsize2 = sizeof(sv_sendclientdatagram_buf);
1193 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)
1195 // no rate limiting support on older protocols because dp protocols
1196 // 1-4 kick the client off if they overflow, and quake protocol shows
1197 // less than the full entity set if rate limited
1203 // PROTOCOL_DARKPLACES5 and later support packet size limiting of updates
1204 maxrate = bound(NET_MINRATE, sv_maxrate.integer, NET_MAXRATE);
1205 if (sv_maxrate.integer != maxrate)
1206 Cvar_SetValueQuick(&sv_maxrate, maxrate);
1208 // this rate limiting does not understand sys_ticrate 0
1209 // (but no one should be running that on a server!)
1210 rate = bound(NET_MINRATE, client->rate, maxrate);
1211 rate = (int)(client->rate * sys_ticrate.value);
1212 maxsize = bound(100, rate, 1400);
1216 msg.data = sv_sendclientdatagram_buf;
1217 msg.maxsize = maxsize;
1220 if (host_client->spawned)
1222 MSG_WriteByte (&msg, svc_time);
1223 MSG_WriteFloat (&msg, sv.time);
1225 // add the client specific data to the datagram
1226 SV_WriteClientdataToMessage (client, client->edict, &msg, stats);
1227 VM_SV_WriteAutoSentStats (client, client->edict, &msg, stats);
1228 SV_WriteEntitiesToClient (client, client->edict, &msg, stats);
1230 // expand packet size to allow effects to go over the rate limit
1231 // (dropping them is FAR too ugly)
1232 msg.maxsize = maxsize2;
1234 // copy the server datagram if there is space
1235 // FIXME: put in delayed queue of effects to send
1236 if (sv.datagram.cursize > 0 && msg.cursize + sv.datagram.cursize <= msg.maxsize)
1237 SZ_Write (&msg, sv.datagram.data, sv.datagram.cursize);
1239 else if (realtime > client->keepalivetime)
1241 // the player isn't totally in the game yet
1242 // send small keepalive messages if too much time has passed
1243 client->keepalivetime = realtime + 5;
1244 MSG_WriteChar (&msg, svc_nop);
1247 // send the datagram
1248 NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol);
1252 =======================
1253 SV_UpdateToReliableMessages
1254 =======================
1256 void SV_UpdateToReliableMessages (void)
1265 // check for changes to be sent over the reliable streams
1266 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1268 // update the host_client fields we care about according to the entity fields
1269 host_client->edict = PRVM_EDICT_NUM(i+1);
1272 name = PRVM_GetString(host_client->edict->fields.server->netname);
1275 // always point the string back at host_client->name to keep it safe
1276 strlcpy (host_client->name, name, sizeof (host_client->name));
1277 host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
1278 if (strcmp(host_client->old_name, host_client->name))
1280 if (host_client->spawned)
1281 SV_BroadcastPrintf("%s changed name to %s\n", host_client->old_name, host_client->name);
1282 strcpy(host_client->old_name, host_client->name);
1283 // send notification to all clients
1284 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
1285 MSG_WriteByte (&sv.reliable_datagram, i);
1286 MSG_WriteString (&sv.reliable_datagram, host_client->name);
1289 // DP_SV_CLIENTCOLORS
1290 // this is always found (since it's added by the progs loader)
1291 if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_clientcolors)))
1292 host_client->colors = (int)val->_float;
1293 if (host_client->old_colors != host_client->colors)
1295 host_client->old_colors = host_client->colors;
1296 // send notification to all clients
1297 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1298 MSG_WriteByte (&sv.reliable_datagram, i);
1299 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1302 // NEXUIZ_PLAYERMODEL
1303 if( eval_playermodel ) {
1304 model = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string);
1307 // always point the string back at host_client->name to keep it safe
1308 strlcpy (host_client->playermodel, model, sizeof (host_client->playermodel));
1309 PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
1312 // NEXUIZ_PLAYERSKIN
1313 if( eval_playerskin ) {
1314 skin = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string);
1317 // always point the string back at host_client->name to keep it safe
1318 strlcpy (host_client->playerskin, skin, sizeof (host_client->playerskin));
1319 PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
1323 host_client->frags = (int)host_client->edict->fields.server->frags;
1324 if (host_client->old_frags != host_client->frags)
1326 host_client->old_frags = host_client->frags;
1327 // send notification to all clients
1328 MSG_WriteByte (&sv.reliable_datagram, svc_updatefrags);
1329 MSG_WriteByte (&sv.reliable_datagram, i);
1330 MSG_WriteShort (&sv.reliable_datagram, host_client->frags);
1334 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1335 if (client->netconnection)
1336 SZ_Write (&client->netconnection->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
1338 SZ_Clear (&sv.reliable_datagram);
1343 =======================
1344 SV_SendClientMessages
1345 =======================
1347 void SV_SendClientMessages (void)
1349 int i, prepared = false;
1351 if (sv.protocol == PROTOCOL_QUAKEWORLD)
1352 Sys_Error("SV_SendClientMessages: no quakeworld support\n");
1354 // update frags, names, etc
1355 SV_UpdateToReliableMessages();
1357 // build individual updates
1358 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1360 if (!host_client->active)
1362 if (!host_client->netconnection)
1365 if (host_client->netconnection->message.overflowed)
1367 SV_DropClient (true); // if the message couldn't send, kick off
1374 // only prepare entities once per frame
1375 SV_PrepareEntitiesForSending();
1377 SV_SendClientDatagram (host_client);
1380 // clear muzzle flashes
1386 ==============================================================================
1390 ==============================================================================
1399 int SV_ModelIndex(const char *s, int precachemode)
1401 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_MODELS);
1402 char filename[MAX_QPATH];
1406 //if (precachemode == 2)
1408 strlcpy(filename, s, sizeof(filename));
1409 for (i = 2;i < limit;i++)
1411 if (!sv.model_precache[i][0])
1415 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))
1417 Con_Printf("SV_ModelIndex(\"%s\"): precache_model can only be done in spawn functions\n", filename);
1420 if (precachemode == 1)
1421 Con_Printf("SV_ModelIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1422 strlcpy(sv.model_precache[i], filename, sizeof(sv.model_precache[i]));
1423 sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, false);
1424 if (sv.state != ss_loading)
1426 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1427 MSG_WriteShort(&sv.reliable_datagram, i);
1428 MSG_WriteString(&sv.reliable_datagram, filename);
1432 Con_Printf("SV_ModelIndex(\"%s\"): not precached\n", filename);
1435 if (!strcmp(sv.model_precache[i], filename))
1438 Con_Printf("SV_ModelIndex(\"%s\"): i (%i) == MAX_MODELS (%i)\n", filename, i, MAX_MODELS);
1448 int SV_SoundIndex(const char *s, int precachemode)
1450 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_SOUNDS);
1451 char filename[MAX_QPATH];
1455 //if (precachemode == 2)
1457 strlcpy(filename, s, sizeof(filename));
1458 for (i = 1;i < limit;i++)
1460 if (!sv.sound_precache[i][0])
1464 if (sv.state != ss_loading && (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5))
1466 Con_Printf("SV_SoundIndex(\"%s\"): precache_sound can only be done in spawn functions\n", filename);
1469 if (precachemode == 1)
1470 Con_Printf("SV_SoundIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1471 strlcpy(sv.sound_precache[i], filename, sizeof(sv.sound_precache[i]));
1472 if (sv.state != ss_loading)
1474 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1475 MSG_WriteShort(&sv.reliable_datagram, i + 32768);
1476 MSG_WriteString(&sv.reliable_datagram, filename);
1480 Con_Printf("SV_SoundIndex(\"%s\"): not precached\n", filename);
1483 if (!strcmp(sv.sound_precache[i], filename))
1486 Con_Printf("SV_SoundIndex(\"%s\"): i (%i) == MAX_SOUNDS (%i)\n", filename, i, MAX_SOUNDS);
1496 void SV_CreateBaseline (void)
1498 int i, entnum, large;
1499 prvm_edict_t *svent;
1501 // LordHavoc: clear *all* states (note just active ones)
1502 for (entnum = 0;entnum < prog->max_edicts;entnum++)
1504 // get the current server version
1505 svent = PRVM_EDICT_NUM(entnum);
1507 // LordHavoc: always clear state values, whether the entity is in use or not
1508 svent->priv.server->baseline = defaultstate;
1510 if (svent->priv.server->free)
1512 if (entnum > svs.maxclients && !svent->fields.server->modelindex)
1515 // create entity baseline
1516 VectorCopy (svent->fields.server->origin, svent->priv.server->baseline.origin);
1517 VectorCopy (svent->fields.server->angles, svent->priv.server->baseline.angles);
1518 svent->priv.server->baseline.frame = (int)svent->fields.server->frame;
1519 svent->priv.server->baseline.skin = (int)svent->fields.server->skin;
1520 if (entnum > 0 && entnum <= svs.maxclients)
1522 svent->priv.server->baseline.colormap = entnum;
1523 svent->priv.server->baseline.modelindex = SV_ModelIndex("progs/player.mdl", 1);
1527 svent->priv.server->baseline.colormap = 0;
1528 svent->priv.server->baseline.modelindex = (int)svent->fields.server->modelindex;
1532 if (svent->priv.server->baseline.modelindex & 0xFF00 || svent->priv.server->baseline.frame & 0xFF00)
1535 // add to the message
1537 MSG_WriteByte (&sv.signon, svc_spawnbaseline2);
1539 MSG_WriteByte (&sv.signon, svc_spawnbaseline);
1540 MSG_WriteShort (&sv.signon, entnum);
1544 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.modelindex);
1545 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.frame);
1549 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.modelindex);
1550 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.frame);
1552 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.colormap);
1553 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.skin);
1554 for (i=0 ; i<3 ; i++)
1556 MSG_WriteCoord(&sv.signon, svent->priv.server->baseline.origin[i], sv.protocol);
1557 MSG_WriteAngle(&sv.signon, svent->priv.server->baseline.angles[i], sv.protocol);
1567 Grabs the current state of each client for saving across the
1568 transition to another level
1571 void SV_SaveSpawnparms (void)
1575 svs.serverflags = (int)prog->globals.server->serverflags;
1577 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1579 if (!host_client->active)
1582 // call the progs to get default spawn parms for the new client
1583 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1584 PRVM_ExecuteProgram (prog->globals.server->SetChangeParms, "QC function SetChangeParms is missing");
1585 for (j=0 ; j<NUM_SPAWN_PARMS ; j++)
1586 host_client->spawn_parms[j] = (&prog->globals.server->parm1)[j];
1590 void SV_IncreaseEdicts(void)
1594 int oldmax_edicts = prog->max_edicts;
1595 void *oldedictsengineprivate = prog->edictprivate;
1596 void *oldedictsfields = prog->edictsfields;
1597 void *oldmoved_edicts = sv.moved_edicts;
1599 if (prog->max_edicts >= MAX_EDICTS)
1602 // links don't survive the transition, so unlink everything
1603 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1605 if (!ent->priv.server->free)
1606 SV_UnlinkEdict(prog->edicts + i);
1607 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
1611 prog->max_edicts = min(prog->max_edicts + 256, MAX_EDICTS);
1612 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
1613 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);
1614 sv.moved_edicts = PR_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1616 memcpy(prog->edictprivate, oldedictsengineprivate, oldmax_edicts * sizeof(edict_engineprivate_t));
1617 memcpy(prog->edictsfields, oldedictsfields, oldmax_edicts * prog->edict_size);
1619 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1621 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
1622 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
1623 // link every entity except world
1624 if (!ent->priv.server->free)
1625 SV_LinkEdict(ent, false);
1628 PR_Free(oldedictsengineprivate);
1629 PR_Free(oldedictsfields);
1630 PR_Free(oldmoved_edicts);
1637 This is called at the start of each level
1640 extern float scr_centertime_off;
1642 void SV_SpawnServer (const char *server)
1647 model_t *worldmodel;
1648 char modelname[sizeof(sv.modelname)];
1650 Con_DPrintf("SpawnServer: %s\n", server);
1652 if (cls.state != ca_dedicated)
1653 SCR_BeginLoadingPlaque();
1655 dpsnprintf (modelname, sizeof(modelname), "maps/%s.bsp", server);
1656 worldmodel = Mod_ForName(modelname, false, true, true);
1657 if (!worldmodel || !worldmodel->TraceBox)
1659 Con_Printf("Couldn't load map %s\n", modelname);
1663 // let's not have any servers with no name
1664 if (hostname.string[0] == 0)
1665 Cvar_Set ("hostname", "UNNAMED");
1666 scr_centertime_off = 0;
1668 svs.changelevel_issued = false; // now safe to issue another
1671 // tell all connected clients that we are going to a new level
1676 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
1678 if (client->netconnection)
1680 MSG_WriteByte(&client->netconnection->message, svc_stufftext);
1681 MSG_WriteString(&client->netconnection->message, "reconnect\n");
1688 NetConn_OpenServerPorts(true);
1692 // make cvars consistant
1695 Cvar_SetValue ("deathmatch", 0);
1696 // LordHavoc: it can be useful to have skills outside the range 0-3...
1697 //current_skill = bound(0, (int)(skill.value + 0.5), 3);
1698 //Cvar_SetValue ("skill", (float)current_skill);
1699 current_skill = (int)(skill.value + 0.5);
1702 // set up the new server
1704 memset (&sv, 0, sizeof(sv));
1705 // if running a local client, make sure it doesn't try to access the last
1706 // level's data which is no longer valiud
1713 strlcpy (sv.name, server, sizeof (sv.name));
1715 sv.protocol = Protocol_EnumForName(sv_protocolname.string);
1716 if (sv.protocol == PROTOCOL_UNKNOWN)
1719 Protocol_Names(buffer, sizeof(buffer));
1720 Con_Printf("Unknown sv_protocolname \"%s\", valid values are:\n%s\n", sv_protocolname.string, buffer);
1721 sv.protocol = PROTOCOL_QUAKE;
1726 // load progs to get entity field count
1727 //PR_LoadProgs ( sv_progs.string );
1729 // allocate server memory
1730 /*// start out with just enough room for clients and a reasonable estimate of entities
1731 prog->max_edicts = max(svs.maxclients + 1, 512);
1732 prog->max_edicts = min(prog->max_edicts, MAX_EDICTS);
1734 // prvm_edict_t structures (hidden from progs)
1735 prog->edicts = PR_Alloc(MAX_EDICTS * sizeof(prvm_edict_t));
1736 // engine private structures (hidden from progs)
1737 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
1738 // progs fields, often accessed by server
1739 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);*/
1740 // used by PushMove to move back pushed entities
1741 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1742 /*for (i = 0;i < prog->max_edicts;i++)
1744 ent = prog->edicts + i;
1745 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
1746 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
1749 // reset client csqc entity versions right away.
1750 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1751 EntityFrameCSQC_InitClientVersions(i, true);
1753 sv.datagram.maxsize = sizeof(sv.datagram_buf);
1754 sv.datagram.cursize = 0;
1755 sv.datagram.data = sv.datagram_buf;
1757 sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf);
1758 sv.reliable_datagram.cursize = 0;
1759 sv.reliable_datagram.data = sv.reliable_datagram_buf;
1761 sv.signon.maxsize = sizeof(sv.signon_buf);
1762 sv.signon.cursize = 0;
1763 sv.signon.data = sv.signon_buf;
1765 // leave slots at start for clients only
1766 //prog->num_edicts = svs.maxclients+1;
1768 sv.state = ss_loading;
1769 prog->allowworldwrites = true;
1772 *prog->time = sv.time = 1.0;
1775 worldmodel->used = true;
1777 strlcpy (sv.name, server, sizeof (sv.name));
1778 strcpy(sv.modelname, modelname);
1779 sv.worldmodel = worldmodel;
1780 sv.models[1] = sv.worldmodel;
1783 // clear world interaction links
1787 strlcpy(sv.sound_precache[0], "", sizeof(sv.sound_precache[0]));
1789 strlcpy(sv.model_precache[0], "", sizeof(sv.model_precache[0]));
1790 strlcpy(sv.model_precache[1], sv.modelname, sizeof(sv.model_precache[1]));
1791 for (i = 1;i < sv.worldmodel->brush.numsubmodels;i++)
1793 dpsnprintf(sv.model_precache[i+1], sizeof(sv.model_precache[i+1]), "*%i", i);
1794 sv.models[i+1] = Mod_ForName (sv.model_precache[i+1], false, false, false);
1798 // load the rest of the entities
1800 // AK possible hack since num_edicts is still 0
1801 ent = PRVM_EDICT_NUM(0);
1802 memset (ent->fields.server, 0, prog->progs->entityfields * 4);
1803 ent->priv.server->free = false;
1804 ent->fields.server->model = PRVM_SetEngineString(sv.modelname);
1805 ent->fields.server->modelindex = 1; // world model
1806 ent->fields.server->solid = SOLID_BSP;
1807 ent->fields.server->movetype = MOVETYPE_PUSH;
1810 prog->globals.server->coop = coop.integer;
1812 prog->globals.server->deathmatch = deathmatch.integer;
1814 prog->globals.server->mapname = PRVM_SetEngineString(sv.name);
1816 // serverflags are for cross level information (sigils)
1817 prog->globals.server->serverflags = svs.serverflags;
1819 // we need to reset the spawned flag on all connected clients here so that
1820 // their thinks don't run during startup (before PutClientInServer)
1821 // we also need to set up the client entities now
1822 // and we need to set the ->edict pointers to point into the progs edicts
1823 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1825 host_client->spawned = false;
1826 host_client->edict = PRVM_EDICT_NUM(i + 1);
1827 PRVM_ED_ClearEdict(host_client->edict);
1830 // load replacement entity file if found
1831 if (sv_entpatch.integer && (entities = (char *)FS_LoadFile(va("maps/%s.ent", sv.name), tempmempool, true, NULL)))
1833 Con_Printf("Loaded maps/%s.ent\n", sv.name);
1834 PRVM_ED_LoadFromFile (entities);
1838 PRVM_ED_LoadFromFile (sv.worldmodel->brush.entities);
1841 // LordHavoc: clear world angles (to fix e3m3.bsp)
1842 VectorClear(prog->edicts->fields.server->angles);
1844 // all setup is completed, any further precache statements are errors
1845 sv.state = ss_active;
1846 prog->allowworldwrites = false;
1848 // run two frames to allow everything to settle
1849 for (i = 0;i < 2;i++)
1857 // create a baseline for more efficient communications
1858 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1859 SV_CreateBaseline ();
1861 // send serverinfo to all connected clients, and set up botclients coming back from a level change
1862 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1864 if (!host_client->active)
1866 if (host_client->netconnection)
1867 SV_SendServerinfo(host_client);
1871 // if client is a botclient coming from a level change, we need to
1872 // set up client info that normally requires networking
1874 // copy spawn parms out of the client_t
1875 for (j=0 ; j< NUM_SPAWN_PARMS ; j++)
1876 (&prog->globals.server->parm1)[j] = host_client->spawn_parms[j];
1878 // call the spawn function
1879 host_client->clientconnectcalled = true;
1880 prog->globals.server->time = sv.time;
1881 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1882 PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
1883 PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
1884 host_client->spawned = true;
1888 Con_DPrint("Server spawned.\n");
1889 NetConn_Heartbeat (2);
1894 /////////////////////////////////////////////////////
1897 void SV_VM_CB_BeginIncreaseEdicts(void)
1902 PRVM_Free( sv.moved_edicts );
1903 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1905 // links don't survive the transition, so unlink everything
1906 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1908 if (!ent->priv.server->free)
1909 SV_UnlinkEdict(prog->edicts + i);
1910 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
1915 void SV_VM_CB_EndIncreaseEdicts(void)
1920 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1922 // link every entity except world
1923 if (!ent->priv.server->free)
1924 SV_LinkEdict(ent, false);
1928 void SV_VM_CB_InitEdict(prvm_edict_t *e)
1930 // LordHavoc: for consistency set these here
1931 int num = PRVM_NUM_FOR_EDICT(e) - 1;
1933 e->priv.server->move = false; // don't move on first frame
1935 if (num >= 0 && num < svs.maxclients)
1938 // set colormap and team on newly created player entity
1939 e->fields.server->colormap = num + 1;
1940 e->fields.server->team = (svs.clients[num].colors & 15) + 1;
1941 // set netname/clientcolors back to client values so that
1942 // DP_SV_CLIENTNAME and DP_SV_CLIENTCOLORS will not immediately
1944 e->fields.server->netname = PRVM_SetEngineString(svs.clients[num].name);
1945 if ((val = PRVM_GETEDICTFIELDVALUE(e, eval_clientcolors)))
1946 val->_float = svs.clients[num].colors;
1947 // NEXUIZ_PLAYERMODEL and NEXUIZ_PLAYERSKIN
1948 if( eval_playermodel )
1949 PRVM_GETEDICTFIELDVALUE(e, eval_playermodel)->string = PRVM_SetEngineString(svs.clients[num].playermodel);
1950 if( eval_playerskin )
1951 PRVM_GETEDICTFIELDVALUE(e, eval_playerskin)->string = PRVM_SetEngineString(svs.clients[num].playerskin);
1955 void SV_VM_CB_FreeEdict(prvm_edict_t *ed)
1957 SV_UnlinkEdict (ed); // unlink from world bsp
1959 ed->fields.server->model = 0;
1960 ed->fields.server->takedamage = 0;
1961 ed->fields.server->modelindex = 0;
1962 ed->fields.server->colormap = 0;
1963 ed->fields.server->skin = 0;
1964 ed->fields.server->frame = 0;
1965 VectorClear(ed->fields.server->origin);
1966 VectorClear(ed->fields.server->angles);
1967 ed->fields.server->nextthink = -1;
1968 ed->fields.server->solid = 0;
1971 void SV_VM_CB_CountEdicts(void)
1975 int active, models, solid, step;
1977 active = models = solid = step = 0;
1978 for (i=0 ; i<prog->num_edicts ; i++)
1980 ent = PRVM_EDICT_NUM(i);
1981 if (ent->priv.server->free)
1984 if (ent->fields.server->solid)
1986 if (ent->fields.server->model)
1988 if (ent->fields.server->movetype == MOVETYPE_STEP)
1992 Con_Printf("num_edicts:%3i\n", prog->num_edicts);
1993 Con_Printf("active :%3i\n", active);
1994 Con_Printf("view :%3i\n", models);
1995 Con_Printf("touch :%3i\n", solid);
1996 Con_Printf("step :%3i\n", step);
1999 qboolean SV_VM_CB_LoadEdict(prvm_edict_t *ent)
2001 // remove things from different skill levels or deathmatch
2002 if (gamemode != GAME_TRANSFUSION) //Transfusion does this in QC
2004 if (deathmatch.integer)
2006 if (((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
2011 else if ((current_skill <= 0 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_EASY ))
2012 || (current_skill == 1 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_MEDIUM))
2013 || (current_skill >= 2 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_HARD )))
2021 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)"};
2022 cvar_t nomonsters = {0, "nomonsters", "0", "unused cvar in quake, can be used by mods"};
2023 cvar_t gamecfg = {0, "gamecfg", "0", "unused cvar in quake, can be used by mods"};
2024 cvar_t scratch1 = {0, "scratch1", "0", "unused cvar in quake, can be used by mods"};
2025 cvar_t scratch2 = {0,"scratch2", "0", "unused cvar in quake, can be used by mods"};
2026 cvar_t scratch3 = {0, "scratch3", "0", "unused cvar in quake, can be used by mods"};
2027 cvar_t scratch4 = {0, "scratch4", "0", "unused cvar in quake, can be used by mods"};
2028 cvar_t savedgamecfg = {CVAR_SAVE, "savedgamecfg", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2029 cvar_t saved1 = {CVAR_SAVE, "saved1", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2030 cvar_t saved2 = {CVAR_SAVE, "saved2", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2031 cvar_t saved3 = {CVAR_SAVE, "saved3", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2032 cvar_t saved4 = {CVAR_SAVE, "saved4", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2033 cvar_t nehx00 = {0, "nehx00", "0", "nehahra data storage cvar (used in singleplayer)"};
2034 cvar_t nehx01 = {0, "nehx01", "0", "nehahra data storage cvar (used in singleplayer)"};
2035 cvar_t nehx02 = {0, "nehx02", "0", "nehahra data storage cvar (used in singleplayer)"};
2036 cvar_t nehx03 = {0, "nehx03", "0", "nehahra data storage cvar (used in singleplayer)"};
2037 cvar_t nehx04 = {0, "nehx04", "0", "nehahra data storage cvar (used in singleplayer)"};
2038 cvar_t nehx05 = {0, "nehx05", "0", "nehahra data storage cvar (used in singleplayer)"};
2039 cvar_t nehx06 = {0, "nehx06", "0", "nehahra data storage cvar (used in singleplayer)"};
2040 cvar_t nehx07 = {0, "nehx07", "0", "nehahra data storage cvar (used in singleplayer)"};
2041 cvar_t nehx08 = {0, "nehx08", "0", "nehahra data storage cvar (used in singleplayer)"};
2042 cvar_t nehx09 = {0, "nehx09", "0", "nehahra data storage cvar (used in singleplayer)"};
2043 cvar_t nehx10 = {0, "nehx10", "0", "nehahra data storage cvar (used in singleplayer)"};
2044 cvar_t nehx11 = {0, "nehx11", "0", "nehahra data storage cvar (used in singleplayer)"};
2045 cvar_t nehx12 = {0, "nehx12", "0", "nehahra data storage cvar (used in singleplayer)"};
2046 cvar_t nehx13 = {0, "nehx13", "0", "nehahra data storage cvar (used in singleplayer)"};
2047 cvar_t nehx14 = {0, "nehx14", "0", "nehahra data storage cvar (used in singleplayer)"};
2048 cvar_t nehx15 = {0, "nehx15", "0", "nehahra data storage cvar (used in singleplayer)"};
2049 cvar_t nehx16 = {0, "nehx16", "0", "nehahra data storage cvar (used in singleplayer)"};
2050 cvar_t nehx17 = {0, "nehx17", "0", "nehahra data storage cvar (used in singleplayer)"};
2051 cvar_t nehx18 = {0, "nehx18", "0", "nehahra data storage cvar (used in singleplayer)"};
2052 cvar_t nehx19 = {0, "nehx19", "0", "nehahra data storage cvar (used in singleplayer)"};
2053 cvar_t cutscene = {0, "cutscene", "1", "enables cutscenes in nehahra, can be used by other mods"};
2055 void SV_VM_Init(void)
2057 Cvar_RegisterVariable (&pr_checkextension);
2058 Cvar_RegisterVariable (&nomonsters);
2059 Cvar_RegisterVariable (&gamecfg);
2060 Cvar_RegisterVariable (&scratch1);
2061 Cvar_RegisterVariable (&scratch2);
2062 Cvar_RegisterVariable (&scratch3);
2063 Cvar_RegisterVariable (&scratch4);
2064 Cvar_RegisterVariable (&savedgamecfg);
2065 Cvar_RegisterVariable (&saved1);
2066 Cvar_RegisterVariable (&saved2);
2067 Cvar_RegisterVariable (&saved3);
2068 Cvar_RegisterVariable (&saved4);
2069 // LordHavoc: Nehahra uses these to pass data around cutscene demos
2070 if (gamemode == GAME_NEHAHRA)
2072 Cvar_RegisterVariable (&nehx00);
2073 Cvar_RegisterVariable (&nehx01);
2074 Cvar_RegisterVariable (&nehx02);
2075 Cvar_RegisterVariable (&nehx03);
2076 Cvar_RegisterVariable (&nehx04);
2077 Cvar_RegisterVariable (&nehx05);
2078 Cvar_RegisterVariable (&nehx06);
2079 Cvar_RegisterVariable (&nehx07);
2080 Cvar_RegisterVariable (&nehx08);
2081 Cvar_RegisterVariable (&nehx09);
2082 Cvar_RegisterVariable (&nehx10);
2083 Cvar_RegisterVariable (&nehx11);
2084 Cvar_RegisterVariable (&nehx12);
2085 Cvar_RegisterVariable (&nehx13);
2086 Cvar_RegisterVariable (&nehx14);
2087 Cvar_RegisterVariable (&nehx15);
2088 Cvar_RegisterVariable (&nehx16);
2089 Cvar_RegisterVariable (&nehx17);
2090 Cvar_RegisterVariable (&nehx18);
2091 Cvar_RegisterVariable (&nehx19);
2093 Cvar_RegisterVariable (&cutscene); // for Nehahra but useful to other mods as well
2096 // LordHavoc: in an effort to eliminate time wasted on GetEdictFieldValue... these are defined as externs in progs.h
2113 int eval_buttonchat;
2115 int eval_glow_trail;
2116 int eval_glow_color;
2120 int eval_renderamt; // HalfLife support
2121 int eval_rendermode; // HalfLife support
2122 int eval_fullbright;
2123 int eval_ammo_shells1;
2124 int eval_ammo_nails1;
2125 int eval_ammo_lava_nails;
2126 int eval_ammo_rockets1;
2127 int eval_ammo_multi_rockets;
2128 int eval_ammo_cells1;
2129 int eval_ammo_plasma;
2130 int eval_idealpitch;
2131 int eval_pitch_speed;
2132 int eval_viewmodelforclient;
2133 int eval_nodrawtoclient;
2134 int eval_exteriormodeltoclient;
2135 int eval_drawonlytoclient;
2139 int eval_punchvector;
2141 int eval_clientcolors;
2142 int eval_tag_entity;
2148 int eval_cursor_active;
2149 int eval_cursor_screen;
2150 int eval_cursor_trace_start;
2151 int eval_cursor_trace_endpos;
2152 int eval_cursor_trace_ent;
2154 int eval_playermodel;
2155 int eval_playerskin;
2156 int eval_SendEntity;
2158 int eval_customizeentityforclient;
2159 int eval_dphitcontentsmask;
2161 int gval_trace_dpstartcontents;
2162 int gval_trace_dphitcontents;
2163 int gval_trace_dphitq3surfaceflags;
2164 int gval_trace_dphittexturename;
2166 mfunction_t *SV_PlayerPhysicsQC;
2167 mfunction_t *EndFrameQC;
2168 //KrimZon - SERVER COMMANDS IN QUAKEC
2169 mfunction_t *SV_ParseClientCommandQC;
2171 ddef_t *PRVM_ED_FindGlobal(const char *name);
2173 void SV_VM_FindEdictFieldOffsets(void)
2175 eval_gravity = PRVM_ED_FindFieldOffset("gravity");
2176 eval_button3 = PRVM_ED_FindFieldOffset("button3");
2177 eval_button4 = PRVM_ED_FindFieldOffset("button4");
2178 eval_button5 = PRVM_ED_FindFieldOffset("button5");
2179 eval_button6 = PRVM_ED_FindFieldOffset("button6");
2180 eval_button7 = PRVM_ED_FindFieldOffset("button7");
2181 eval_button8 = PRVM_ED_FindFieldOffset("button8");
2182 eval_button9 = PRVM_ED_FindFieldOffset("button9");
2183 eval_button10 = PRVM_ED_FindFieldOffset("button10");
2184 eval_button11 = PRVM_ED_FindFieldOffset("button11");
2185 eval_button12 = PRVM_ED_FindFieldOffset("button12");
2186 eval_button13 = PRVM_ED_FindFieldOffset("button13");
2187 eval_button14 = PRVM_ED_FindFieldOffset("button14");
2188 eval_button15 = PRVM_ED_FindFieldOffset("button15");
2189 eval_button16 = PRVM_ED_FindFieldOffset("button16");
2190 eval_buttonuse = PRVM_ED_FindFieldOffset("buttonuse");
2191 eval_buttonchat = PRVM_ED_FindFieldOffset("buttonchat");
2192 eval_glow_size = PRVM_ED_FindFieldOffset("glow_size");
2193 eval_glow_trail = PRVM_ED_FindFieldOffset("glow_trail");
2194 eval_glow_color = PRVM_ED_FindFieldOffset("glow_color");
2195 eval_items2 = PRVM_ED_FindFieldOffset("items2");
2196 eval_scale = PRVM_ED_FindFieldOffset("scale");
2197 eval_alpha = PRVM_ED_FindFieldOffset("alpha");
2198 eval_renderamt = PRVM_ED_FindFieldOffset("renderamt"); // HalfLife support
2199 eval_rendermode = PRVM_ED_FindFieldOffset("rendermode"); // HalfLife support
2200 eval_fullbright = PRVM_ED_FindFieldOffset("fullbright");
2201 eval_ammo_shells1 = PRVM_ED_FindFieldOffset("ammo_shells1");
2202 eval_ammo_nails1 = PRVM_ED_FindFieldOffset("ammo_nails1");
2203 eval_ammo_lava_nails = PRVM_ED_FindFieldOffset("ammo_lava_nails");
2204 eval_ammo_rockets1 = PRVM_ED_FindFieldOffset("ammo_rockets1");
2205 eval_ammo_multi_rockets = PRVM_ED_FindFieldOffset("ammo_multi_rockets");
2206 eval_ammo_cells1 = PRVM_ED_FindFieldOffset("ammo_cells1");
2207 eval_ammo_plasma = PRVM_ED_FindFieldOffset("ammo_plasma");
2208 eval_idealpitch = PRVM_ED_FindFieldOffset("idealpitch");
2209 eval_pitch_speed = PRVM_ED_FindFieldOffset("pitch_speed");
2210 eval_viewmodelforclient = PRVM_ED_FindFieldOffset("viewmodelforclient");
2211 eval_nodrawtoclient = PRVM_ED_FindFieldOffset("nodrawtoclient");
2212 eval_exteriormodeltoclient = PRVM_ED_FindFieldOffset("exteriormodeltoclient");
2213 eval_drawonlytoclient = PRVM_ED_FindFieldOffset("drawonlytoclient");
2214 eval_ping = PRVM_ED_FindFieldOffset("ping");
2215 eval_movement = PRVM_ED_FindFieldOffset("movement");
2216 eval_pmodel = PRVM_ED_FindFieldOffset("pmodel");
2217 eval_punchvector = PRVM_ED_FindFieldOffset("punchvector");
2218 eval_viewzoom = PRVM_ED_FindFieldOffset("viewzoom");
2219 eval_clientcolors = PRVM_ED_FindFieldOffset("clientcolors");
2220 eval_tag_entity = PRVM_ED_FindFieldOffset("tag_entity");
2221 eval_tag_index = PRVM_ED_FindFieldOffset("tag_index");
2222 eval_light_lev = PRVM_ED_FindFieldOffset("light_lev");
2223 eval_color = PRVM_ED_FindFieldOffset("color");
2224 eval_style = PRVM_ED_FindFieldOffset("style");
2225 eval_pflags = PRVM_ED_FindFieldOffset("pflags");
2226 eval_cursor_active = PRVM_ED_FindFieldOffset("cursor_active");
2227 eval_cursor_screen = PRVM_ED_FindFieldOffset("cursor_screen");
2228 eval_cursor_trace_start = PRVM_ED_FindFieldOffset("cursor_trace_start");
2229 eval_cursor_trace_endpos = PRVM_ED_FindFieldOffset("cursor_trace_endpos");
2230 eval_cursor_trace_ent = PRVM_ED_FindFieldOffset("cursor_trace_ent");
2231 eval_colormod = PRVM_ED_FindFieldOffset("colormod");
2232 eval_playermodel = PRVM_ED_FindFieldOffset("playermodel");
2233 eval_playerskin = PRVM_ED_FindFieldOffset("playerskin");
2234 eval_SendEntity = PRVM_ED_FindFieldOffset("SendEntity");
2235 eval_Version = PRVM_ED_FindFieldOffset("Version");
2236 eval_customizeentityforclient = PRVM_ED_FindFieldOffset("customizeentityforclient");
2237 eval_dphitcontentsmask = PRVM_ED_FindFieldOffset("dphitcontentsmask");
2239 // LordHavoc: allowing QuakeC to override the player movement code
2240 SV_PlayerPhysicsQC = PRVM_ED_FindFunction ("SV_PlayerPhysics");
2241 // LordHavoc: support for endframe
2242 EndFrameQC = PRVM_ED_FindFunction ("EndFrame");
2243 //KrimZon - SERVER COMMANDS IN QUAKEC
2244 SV_ParseClientCommandQC = PRVM_ED_FindFunction ("SV_ParseClientCommand");
2246 //[515]: init stufftext string (it is sent before svc_serverinfo)
2247 if(PRVM_ED_FindGlobal("SV_InitCmd") && PRVM_ED_FindGlobal("SV_InitCmd")->type & ev_string)
2248 SV_InitCmd = PRVM_G_STRING(PRVM_ED_FindGlobal("SV_InitCmd")->ofs);
2252 gval_trace_dpstartcontents = PRVM_ED_FindGlobalOffset("trace_dpstartcontents");
2253 gval_trace_dphitcontents = PRVM_ED_FindGlobalOffset("trace_dphitcontents");
2254 gval_trace_dphitq3surfaceflags = PRVM_ED_FindGlobalOffset("trace_dphitq3surfaceflags");
2255 gval_trace_dphittexturename = PRVM_ED_FindGlobalOffset("trace_dphittexturename");
2258 #define REQFIELDS (sizeof(reqfields) / sizeof(prvm_required_field_t))
2260 prvm_required_field_t reqfields[] =
2262 {ev_entity, "cursor_trace_ent"},
2263 {ev_entity, "drawonlytoclient"},
2264 {ev_entity, "exteriormodeltoclient"},
2265 {ev_entity, "nodrawtoclient"},
2266 {ev_entity, "tag_entity"},
2267 {ev_entity, "viewmodelforclient"},
2268 {ev_float, "alpha"},
2269 {ev_float, "ammo_cells1"},
2270 {ev_float, "ammo_lava_nails"},
2271 {ev_float, "ammo_multi_rockets"},
2272 {ev_float, "ammo_nails1"},
2273 {ev_float, "ammo_plasma"},
2274 {ev_float, "ammo_rockets1"},
2275 {ev_float, "ammo_shells1"},
2276 {ev_float, "button3"},
2277 {ev_float, "button4"},
2278 {ev_float, "button5"},
2279 {ev_float, "button6"},
2280 {ev_float, "button7"},
2281 {ev_float, "button8"},
2282 {ev_float, "button9"},
2283 {ev_float, "button10"},
2284 {ev_float, "button11"},
2285 {ev_float, "button12"},
2286 {ev_float, "button13"},
2287 {ev_float, "button14"},
2288 {ev_float, "button15"},
2289 {ev_float, "button16"},
2290 {ev_float, "buttonchat"},
2291 {ev_float, "buttonuse"},
2292 {ev_float, "clientcolors"},
2293 {ev_float, "cursor_active"},
2294 {ev_float, "fullbright"},
2295 {ev_float, "glow_color"},
2296 {ev_float, "glow_size"},
2297 {ev_float, "glow_trail"},
2298 {ev_float, "gravity"},
2299 {ev_float, "idealpitch"},
2300 {ev_float, "items2"},
2301 {ev_float, "light_lev"},
2302 {ev_float, "pflags"},
2304 {ev_float, "pitch_speed"},
2305 {ev_float, "pmodel"},
2306 {ev_float, "renderamt"}, // HalfLife support
2307 {ev_float, "rendermode"}, // HalfLife support
2308 {ev_float, "scale"},
2309 {ev_float, "style"},
2310 {ev_float, "tag_index"},
2311 {ev_float, "Version"},
2312 {ev_float, "viewzoom"},
2313 {ev_vector, "color"},
2314 {ev_vector, "colormod"},
2315 {ev_vector, "cursor_screen"},
2316 {ev_vector, "cursor_trace_endpos"},
2317 {ev_vector, "cursor_trace_start"},
2318 {ev_vector, "movement"},
2319 {ev_vector, "punchvector"},
2320 {ev_string, "playermodel"},
2321 {ev_string, "playerskin"},
2322 {ev_function, "SendEntity"},
2323 {ev_function, "customizeentityforclient"},
2326 void SV_VM_Setup(void)
2329 PRVM_InitProg( PRVM_SERVERPROG );
2331 // allocate the mempools
2332 prog->progs_mempool = Mem_AllocPool("Server Progs", 0, NULL);
2333 prog->builtins = vm_sv_builtins;
2334 prog->numbuiltins = vm_sv_numbuiltins;
2335 prog->headercrc = PROGHEADER_CRC;
2336 prog->max_edicts = 512;
2337 prog->limit_edicts = MAX_EDICTS;
2338 prog->reserved_edicts = svs.maxclients;
2339 prog->edictprivate_size = sizeof(edict_engineprivate_t);
2340 prog->name = "server";
2341 prog->extensionstring = vm_sv_extensions;
2342 prog->loadintoworld = true;
2344 prog->begin_increase_edicts = SV_VM_CB_BeginIncreaseEdicts;
2345 prog->end_increase_edicts = SV_VM_CB_EndIncreaseEdicts;
2346 prog->init_edict = SV_VM_CB_InitEdict;
2347 prog->free_edict = SV_VM_CB_FreeEdict;
2348 prog->count_edicts = SV_VM_CB_CountEdicts;
2349 prog->load_edict = SV_VM_CB_LoadEdict;
2350 prog->init_cmd = VM_SV_Cmd_Init;
2351 prog->reset_cmd = VM_SV_Cmd_Reset;
2352 prog->error_cmd = Host_Error;
2354 // TODO: add a requiredfuncs list (ask LH if this is necessary at all)
2355 PRVM_LoadProgs( sv_progs.string, 0, NULL, REQFIELDS, reqfields );
2356 SV_VM_FindEdictFieldOffsets();
2358 VM_AutoSentStats_Clear();//[515]: csqc
2359 EntityFrameCSQC_ClearVersions();//[515]: csqc
2364 void SV_VM_Begin(void)
2367 PRVM_SetProg( PRVM_SERVERPROG );
2369 *prog->time = (float) sv.time;
2372 void SV_VM_End(void)