diff options
Diffstat (limited to 'samples/quake/jni/sv_main.cpp')
-rw-r--r-- | samples/quake/jni/sv_main.cpp | 1200 |
1 files changed, 0 insertions, 1200 deletions
diff --git a/samples/quake/jni/sv_main.cpp b/samples/quake/jni/sv_main.cpp deleted file mode 100644 index b75bfad..0000000 --- a/samples/quake/jni/sv_main.cpp +++ /dev/null @@ -1,1200 +0,0 @@ -/* -Copyright (C) 1996-1997 Id Software, Inc. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ -// sv_main.c -- server main program - -#include "quakedef.h" - -server_t sv; -server_static_t svs; - -char localmodels[MAX_MODELS][5]; // inline model names for precache - -//============================================================================ - -/* -=============== -SV_Init -=============== -*/ -void SV_Init (void) -{ - int i; - extern cvar_t sv_maxvelocity; - extern cvar_t sv_gravity; - extern cvar_t sv_nostep; - extern cvar_t sv_friction; - extern cvar_t sv_edgefriction; - extern cvar_t sv_stopspeed; - extern cvar_t sv_maxspeed; - extern cvar_t sv_accelerate; - extern cvar_t sv_idealpitchscale; - extern cvar_t sv_aim; - - Cvar_RegisterVariable (&sv_maxvelocity); - Cvar_RegisterVariable (&sv_gravity); - Cvar_RegisterVariable (&sv_friction); - Cvar_RegisterVariable (&sv_edgefriction); - Cvar_RegisterVariable (&sv_stopspeed); - Cvar_RegisterVariable (&sv_maxspeed); - Cvar_RegisterVariable (&sv_accelerate); - Cvar_RegisterVariable (&sv_idealpitchscale); - Cvar_RegisterVariable (&sv_aim); - Cvar_RegisterVariable (&sv_nostep); - - for (i=0 ; i<MAX_MODELS ; i++) - sprintf (localmodels[i], "*%i", i); -} - -/* -============================================================================= - -EVENT MESSAGES - -============================================================================= -*/ - -/* -================== -SV_StartParticle - -Make sure the event gets sent to all clients -================== -*/ -void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count) -{ - int i, v; - - if (sv.datagram.cursize > MAX_DATAGRAM-16) - return; - MSG_WriteByte (&sv.datagram, svc_particle); - MSG_WriteCoord (&sv.datagram, org[0]); - MSG_WriteCoord (&sv.datagram, org[1]); - MSG_WriteCoord (&sv.datagram, org[2]); - for (i=0 ; i<3 ; i++) - { - v = (int)(dir[i]*16); - if (v > 127) - v = 127; - else if (v < -128) - v = -128; - MSG_WriteChar (&sv.datagram, v); - } - MSG_WriteByte (&sv.datagram, count); - MSG_WriteByte (&sv.datagram, color); -} - -/* -================== -SV_StartSound - -Each entity can have eight independant sound sources, like voice, -weapon, feet, etc. - -Channel 0 is an auto-allocate channel, the others override anything -allready running on that entity/channel pair. - -An attenuation of 0 will play full volume everywhere in the level. -Larger attenuations will drop off. (max 4 attenuation) - -================== -*/ -void SV_StartSound (edict_t *entity, int channel, const char *sample, int volume, - float attenuation) -{ - int sound_num; - int field_mask; - int i; - int ent; - - if (volume < 0 || volume > 255) - Sys_Error ("SV_StartSound: volume = %i", volume); - - if (attenuation < 0 || attenuation > 4) - Sys_Error ("SV_StartSound: attenuation = %f", attenuation); - - if (channel < 0 || channel > 7) - Sys_Error ("SV_StartSound: channel = %i", channel); - - if (sv.datagram.cursize > MAX_DATAGRAM-16) - return; - -// find precache number for sound - for (sound_num=1 ; sound_num<MAX_SOUNDS - && sv.sound_precache[sound_num] ; sound_num++) - if (!strcmp(sample, sv.sound_precache[sound_num])) - break; - - if ( sound_num == MAX_SOUNDS || !sv.sound_precache[sound_num] ) - { - Con_Printf ("SV_StartSound: %s not precacheed\n", sample); - return; - } - - ent = NUM_FOR_EDICT(entity); - - channel = (ent<<3) | channel; - - field_mask = 0; - if (volume != DEFAULT_SOUND_PACKET_VOLUME) - field_mask |= SND_VOLUME; - if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION) - field_mask |= SND_ATTENUATION; - -// directed messages go only to the entity the are targeted on - MSG_WriteByte (&sv.datagram, svc_sound); - MSG_WriteByte (&sv.datagram, field_mask); - if (field_mask & SND_VOLUME) - MSG_WriteByte (&sv.datagram, volume); - if (field_mask & SND_ATTENUATION) - MSG_WriteByte (&sv.datagram, (int) (attenuation*64)); - MSG_WriteShort (&sv.datagram, channel); - MSG_WriteByte (&sv.datagram, sound_num); - for (i=0 ; i<3 ; i++) - MSG_WriteCoord (&sv.datagram, entity->u.v.origin[i]+0.5*(entity->u.v.mins[i]+entity->u.v.maxs[i])); -} - -/* -============================================================================== - -CLIENT SPAWNING - -============================================================================== -*/ - -/* -================ -SV_SendServerinfo - -Sends the first message from the server to a connected client. -This will be sent on the initial connection and upon each server load. -================ -*/ -void SV_SendServerinfo (client_t *client) -{ - char **s; - char message[2048]; - - MSG_WriteByte (&client->message, svc_print); - sprintf (message, "%c\nVERSION %4.2f SERVER (%i CRC)", 2, VERSION, pr_crc); - MSG_WriteString (&client->message,message); - - MSG_WriteByte (&client->message, svc_serverinfo); - MSG_WriteLong (&client->message, PROTOCOL_VERSION); - MSG_WriteByte (&client->message, svs.maxclients); - - if (!coop.value && deathmatch.value) - MSG_WriteByte (&client->message, GAME_DEATHMATCH); - else - MSG_WriteByte (&client->message, GAME_COOP); - - sprintf (message, "%s", pr_strings+sv.edicts->u.v.message); - - MSG_WriteString (&client->message,message); - - for (s = sv.model_precache+1 ; *s ; s++) - MSG_WriteString (&client->message, *s); - MSG_WriteByte (&client->message, 0); - - for (s = sv.sound_precache+1 ; *s ; s++) - MSG_WriteString (&client->message, *s); - MSG_WriteByte (&client->message, 0); - -// send music - MSG_WriteByte (&client->message, svc_cdtrack); - MSG_WriteByte (&client->message, (int) sv.edicts->u.v.sounds); - MSG_WriteByte (&client->message, (int) sv.edicts->u.v.sounds); - -// set view - MSG_WriteByte (&client->message, svc_setview); - MSG_WriteShort (&client->message, NUM_FOR_EDICT(client->edict)); - - MSG_WriteByte (&client->message, svc_signonnum); - MSG_WriteByte (&client->message, 1); - - client->sendsignon = true; - client->spawned = false; // need prespawn, spawn, etc -} - -/* -================ -SV_ConnectClient - -Initializes a client_t for a new net connection. This will only be called -once for a player each game, not once for each level change. -================ -*/ -void SV_ConnectClient (int clientnum) -{ - edict_t *ent; - client_t *client; - int edictnum; - struct qsocket_s *netconnection; - int i; - float spawn_parms[NUM_SPAWN_PARMS] = {}; - - client = svs.clients + clientnum; - - Con_DPrintf ("Client %s connected\n", client->netconnection->address); - - edictnum = clientnum+1; - - ent = EDICT_NUM(edictnum); - -// set up the client_t - netconnection = client->netconnection; - - if (sv.loadgame) - memcpy (spawn_parms, client->spawn_parms, sizeof(spawn_parms)); - memset (client, 0, sizeof(*client)); - client->netconnection = netconnection; - - strcpy (client->name, "unconnected"); - client->active = true; - client->spawned = false; - client->edict = ent; - client->message.data = client->msgbuf; - client->message.maxsize = sizeof(client->msgbuf); - client->message.allowoverflow = true; // we can catch it - -#ifdef IDGODS - client->privileged = IsID(&client->netconnection->addr); -#else - client->privileged = false; -#endif - - if (sv.loadgame) - memcpy (client->spawn_parms, spawn_parms, sizeof(spawn_parms)); - else - { - // call the progs to get default spawn parms for the new client - PR_ExecuteProgram (pr_global_struct->SetNewParms); - for (i=0 ; i<NUM_SPAWN_PARMS ; i++) - client->spawn_parms[i] = (&pr_global_struct->parm1)[i]; - } - - SV_SendServerinfo (client); -} - - -/* -=================== -SV_CheckForNewClients - -=================== -*/ -void SV_CheckForNewClients (void) -{ - struct qsocket_s *ret; - int i; - -// -// check for new connections -// - while (1) - { - ret = NET_CheckNewConnections (); - if (!ret) - break; - - // - // init a new client structure - // - for (i=0 ; i<svs.maxclients ; i++) - if (!svs.clients[i].active) - break; - if (i == svs.maxclients) - Sys_Error ("Host_CheckForNewClients: no free clients"); - - svs.clients[i].netconnection = ret; - SV_ConnectClient (i); - - net_activeconnections++; - } -} - - - -/* -=============================================================================== - -FRAME UPDATES - -=============================================================================== -*/ - -/* -================== -SV_ClearDatagram - -================== -*/ -void SV_ClearDatagram (void) -{ - SZ_Clear (&sv.datagram); -} - -/* -============================================================================= - -The PVS must include a small area around the client to allow head bobbing -or other small motion on the client side. Otherwise, a bob might cause an -entity that should be visible to not show up, especially when the bob -crosses a waterline. - -============================================================================= -*/ - -int fatbytes; -byte fatpvs[MAX_MAP_LEAFS/8]; - -void SV_AddToFatPVS (vec3_t org, mnode_t *node) -{ - int i; - byte *pvs; - mplane_t *plane; - float d; - - while (1) - { - // if this is a leaf, accumulate the pvs bits - if (node->contents < 0) - { - if (node->contents != CONTENTS_SOLID) - { - pvs = Mod_LeafPVS ( (mleaf_t *)node, sv.worldmodel); - for (i=0 ; i<fatbytes ; i++) - fatpvs[i] |= pvs[i]; - } - return; - } - - plane = node->plane; - d = DotProduct (org, plane->normal) - plane->dist; - if (d > 8) - node = node->children[0]; - else if (d < -8) - node = node->children[1]; - else - { // go down both - SV_AddToFatPVS (org, node->children[0]); - node = node->children[1]; - } - } -} - -/* -============= -SV_FatPVS - -Calculates a PVS that is the inclusive or of all leafs within 8 pixels of the -given point. -============= -*/ -byte *SV_FatPVS (vec3_t org) -{ - fatbytes = (sv.worldmodel->numleafs+31)>>3; - Q_memset (fatpvs, 0, fatbytes); - SV_AddToFatPVS (org, sv.worldmodel->nodes); - return fatpvs; -} - -//============================================================================= - - -/* -============= -SV_WriteEntitiesToClient - -============= -*/ -void SV_WriteEntitiesToClient (edict_t *clent, sizebuf_t *msg) -{ - int e, i; - int bits; - byte *pvs; - vec3_t org; - float miss; - edict_t *ent; - -// find the client's PVS - VectorAdd (clent->u.v.origin, clent->u.v.view_ofs, org); - pvs = SV_FatPVS (org); - -// send over all entities (excpet the client) that touch the pvs - ent = NEXT_EDICT(sv.edicts); - for (e=1 ; e<sv.num_edicts ; e++, ent = NEXT_EDICT(ent)) - { -#ifdef QUAKE2 - // don't send if flagged for NODRAW and there are no lighting effects - if (ent->u.v.effects == EF_NODRAW) - continue; -#endif - -// ignore if not touching a PV leaf - if (ent != clent) // clent is ALLWAYS sent - { -// ignore ents without visible models - if (!ent->u.v.modelindex || !pr_strings[ent->u.v.model]) - continue; - - for (i=0 ; i < ent->num_leafs ; i++) - if (pvs[ent->leafnums[i] >> 3] & (1 << (ent->leafnums[i]&7) )) - break; - - if (i == ent->num_leafs) - continue; // not visible - } - - if (msg->maxsize - msg->cursize < 16) - { - Con_Printf ("packet overflow\n"); - return; - } - -// send an update - bits = 0; - - for (i=0 ; i<3 ; i++) - { - miss = ent->u.v.origin[i] - ent->baseline.origin[i]; - if ( miss < -0.1 || miss > 0.1 ) - bits |= U_ORIGIN1<<i; - } - - if ( ent->u.v.angles[0] != ent->baseline.angles[0] ) - bits |= U_ANGLE1; - - if ( ent->u.v.angles[1] != ent->baseline.angles[1] ) - bits |= U_ANGLE2; - - if ( ent->u.v.angles[2] != ent->baseline.angles[2] ) - bits |= U_ANGLE3; - - if (ent->u.v.movetype == MOVETYPE_STEP) - bits |= U_NOLERP; // don't mess up the step animation - - if (ent->baseline.colormap != ent->u.v.colormap) - bits |= U_COLORMAP; - - if (ent->baseline.skin != ent->u.v.skin) - bits |= U_SKIN; - - if (ent->baseline.frame != ent->u.v.frame) - bits |= U_FRAME; - - if (ent->baseline.effects != ent->u.v.effects) - bits |= U_EFFECTS; - - if (ent->baseline.modelindex != ent->u.v.modelindex) - bits |= U_MODEL; - - if (e >= 256) - bits |= U_LONGENTITY; - - if (bits >= 256) - bits |= U_MOREBITS; - - // - // write the message - // - MSG_WriteByte (msg,bits | U_SIGNAL); - - if (bits & U_MOREBITS) - MSG_WriteByte (msg, bits>>8); - if (bits & U_LONGENTITY) - MSG_WriteShort (msg,e); - else - MSG_WriteByte (msg,e); - - if (bits & U_MODEL) - MSG_WriteByte (msg, (int) ent->u.v.modelindex); - if (bits & U_FRAME) - MSG_WriteByte (msg, (int) ent->u.v.frame); - if (bits & U_COLORMAP) - MSG_WriteByte (msg, (int) ent->u.v.colormap); - if (bits & U_SKIN) - MSG_WriteByte (msg, (int) ent->u.v.skin); - if (bits & U_EFFECTS) - MSG_WriteByte (msg, (int) ent->u.v.effects); - if (bits & U_ORIGIN1) - MSG_WriteCoord (msg, ent->u.v.origin[0]); - if (bits & U_ANGLE1) - MSG_WriteAngle(msg, ent->u.v.angles[0]); - if (bits & U_ORIGIN2) - MSG_WriteCoord (msg, ent->u.v.origin[1]); - if (bits & U_ANGLE2) - MSG_WriteAngle(msg, ent->u.v.angles[1]); - if (bits & U_ORIGIN3) - MSG_WriteCoord (msg, ent->u.v.origin[2]); - if (bits & U_ANGLE3) - MSG_WriteAngle(msg, ent->u.v.angles[2]); - } -} - -/* -============= -SV_CleanupEnts - -============= -*/ -void SV_CleanupEnts (void) -{ - int e; - edict_t *ent; - - ent = NEXT_EDICT(sv.edicts); - for (e=1 ; e<sv.num_edicts ; e++, ent = NEXT_EDICT(ent)) - { - ent->u.v.effects = (int)ent->u.v.effects & ~EF_MUZZLEFLASH; - } - -} - -/* -================== -SV_WriteClientdataToMessage - -================== -*/ -void SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg) -{ - int bits; - int i; - edict_t *other; - int items; -#ifndef QUAKE2 - eval_t *val; -#endif - -// -// send a damage message -// - if (ent->u.v.dmg_take || ent->u.v.dmg_save) - { - other = PROG_TO_EDICT(ent->u.v.dmg_inflictor); - MSG_WriteByte (msg, svc_damage); - MSG_WriteByte (msg, (int) ent->u.v.dmg_save); - MSG_WriteByte (msg, (int) ent->u.v.dmg_take); - for (i=0 ; i<3 ; i++) - MSG_WriteCoord (msg, other->u.v.origin[i] + 0.5*(other->u.v.mins[i] + other->u.v.maxs[i])); - - ent->u.v.dmg_take = 0; - ent->u.v.dmg_save = 0; - } - -// -// send the current viewpos offset from the view entity -// - SV_SetIdealPitch (); // how much to look up / down ideally - -// a fixangle might get lost in a dropped packet. Oh well. - if ( ent->u.v.fixangle ) - { - MSG_WriteByte (msg, svc_setangle); - for (i=0 ; i < 3 ; i++) - MSG_WriteAngle (msg, ent->u.v.angles[i] ); - ent->u.v.fixangle = 0; - } - - bits = 0; - - if (ent->u.v.view_ofs[2] != DEFAULT_VIEWHEIGHT) - bits |= SU_VIEWHEIGHT; - - if (ent->u.v.idealpitch) - bits |= SU_IDEALPITCH; - -// stuff the sigil bits into the high bits of items for sbar, or else -// mix in items2 -#ifdef QUAKE2 - items = (int)ent->u.v.items | ((int)ent->u.v.items2 << 23); -#else - val = GetEdictFieldValue(ent, "items2"); - - if (val) - items = (int)ent->u.v.items | ((int)val->_float << 23); - else - items = (int)ent->u.v.items | ((int)pr_global_struct->serverflags << 28); -#endif - - bits |= SU_ITEMS; - - if ( (int)ent->u.v.flags & FL_ONGROUND) - bits |= SU_ONGROUND; - - if ( ent->u.v.waterlevel >= 2) - bits |= SU_INWATER; - - for (i=0 ; i<3 ; i++) - { - if (ent->u.v.punchangle[i]) - bits |= (SU_PUNCH1<<i); - if (ent->u.v.velocity[i]) - bits |= (SU_VELOCITY1<<i); - } - - if (ent->u.v.weaponframe) - bits |= SU_WEAPONFRAME; - - if (ent->u.v.armorvalue) - bits |= SU_ARMOR; - -// if (ent->u.v.weapon) - bits |= SU_WEAPON; - -// send the data - - MSG_WriteByte (msg, svc_clientdata); - MSG_WriteShort (msg, bits); - - if (bits & SU_VIEWHEIGHT) - MSG_WriteChar (msg, (int) ent->u.v.view_ofs[2]); - - if (bits & SU_IDEALPITCH) - MSG_WriteChar (msg, (int) ent->u.v.idealpitch); - - for (i=0 ; i<3 ; i++) - { - if (bits & (SU_PUNCH1<<i)) - MSG_WriteChar (msg, (int) ent->u.v.punchangle[i]); - if (bits & (SU_VELOCITY1<<i)) - MSG_WriteChar (msg, (int) ent->u.v.velocity[i]/16); - } - -// [always sent] if (bits & SU_ITEMS) - MSG_WriteLong (msg, items); - - if (bits & SU_WEAPONFRAME) - MSG_WriteByte (msg, (int) ent->u.v.weaponframe); - if (bits & SU_ARMOR) - MSG_WriteByte (msg, (int) ent->u.v.armorvalue); - if (bits & SU_WEAPON) - MSG_WriteByte (msg, SV_ModelIndex(pr_strings+ent->u.v.weaponmodel)); - - MSG_WriteShort (msg, (int) ent->u.v.health); - MSG_WriteByte (msg, (int) ent->u.v.currentammo); - MSG_WriteByte (msg, (int) ent->u.v.ammo_shells); - MSG_WriteByte (msg, (int) ent->u.v.ammo_nails); - MSG_WriteByte (msg, (int) ent->u.v.ammo_rockets); - MSG_WriteByte (msg, (int) ent->u.v.ammo_cells); - - if (standard_quake) - { - MSG_WriteByte (msg, (int) ent->u.v.weapon); - } - else - { - for(i=0;i<32;i++) - { - if ( ((int)ent->u.v.weapon) & (1<<i) ) - { - MSG_WriteByte (msg, i); - break; - } - } - } -} - -/* -======================= -SV_SendClientDatagram -======================= -*/ -qboolean SV_SendClientDatagram (client_t *client) -{ - byte buf[MAX_DATAGRAM]; - sizebuf_t msg; - - msg.data = buf; - msg.maxsize = sizeof(buf); - msg.cursize = 0; - - MSG_WriteByte (&msg, svc_time); - MSG_WriteFloat (&msg, sv.time); - -// add the client specific data to the datagram - SV_WriteClientdataToMessage (client->edict, &msg); - - SV_WriteEntitiesToClient (client->edict, &msg); - -// copy the server datagram if there is space - if (msg.cursize + sv.datagram.cursize < msg.maxsize) - SZ_Write (&msg, sv.datagram.data, sv.datagram.cursize); - -// send the datagram - if (NET_SendUnreliableMessage (client->netconnection, &msg) == -1) - { - SV_DropClient (true);// if the message couldn't send, kick off - return false; - } - - return true; -} - -/* -======================= -SV_UpdateToReliableMessages -======================= -*/ -void SV_UpdateToReliableMessages (void) -{ - int i, j; - client_t *client; - -// check for changes to be sent over the reliable streams - for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++) - { - if (host_client->old_frags != host_client->edict->u.v.frags) - { - for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++) - { - if (!client->active) - continue; - MSG_WriteByte (&client->message, svc_updatefrags); - MSG_WriteByte (&client->message, i); - MSG_WriteShort (&client->message, (int) host_client->edict->u.v.frags); - } - - host_client->old_frags = (int) host_client->edict->u.v.frags; - } - } - - for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++) - { - if (!client->active) - continue; - SZ_Write (&client->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize); - } - - SZ_Clear (&sv.reliable_datagram); -} - - -/* -======================= -SV_SendNop - -Send a nop message without trashing or sending the accumulated client -message buffer -======================= -*/ -void SV_SendNop (client_t *client) -{ - sizebuf_t msg; - byte buf[4]; - - msg.data = buf; - msg.maxsize = sizeof(buf); - msg.cursize = 0; - - MSG_WriteChar (&msg, svc_nop); - - if (NET_SendUnreliableMessage (client->netconnection, &msg) == -1) - SV_DropClient (true); // if the message couldn't send, kick off - client->last_message = realtime; -} - -/* -======================= -SV_SendClientMessages -======================= -*/ -void SV_SendClientMessages (void) -{ - int i; - -// update frags, names, etc - SV_UpdateToReliableMessages (); - -// build individual updates - for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++) - { - if (!host_client->active) - continue; - - if (host_client->spawned) - { - if (!SV_SendClientDatagram (host_client)) - continue; - } - else - { - // the player isn't totally in the game yet - // send small keepalive messages if too much time has passed - // send a full message when the next signon stage has been requested - // some other message data (name changes, etc) may accumulate - // between signon stages - if (!host_client->sendsignon) - { - if (realtime - host_client->last_message > 5) - SV_SendNop (host_client); - continue; // don't send out non-signon messages - } - } - - // check for an overflowed message. Should only happen - // on a very fucked up connection that backs up a lot, then - // changes level - if (host_client->message.overflowed) - { - SV_DropClient (true); - host_client->message.overflowed = false; - continue; - } - - if (host_client->message.cursize || host_client->dropasap) - { - if (!NET_CanSendMessage (host_client->netconnection)) - { -// I_Printf ("can't write\n"); - continue; - } - - if (host_client->dropasap) - SV_DropClient (false); // went to another level - else - { - if (NET_SendMessage (host_client->netconnection - , &host_client->message) == -1) - SV_DropClient (true); // if the message couldn't send, kick off - SZ_Clear (&host_client->message); - host_client->last_message = realtime; - host_client->sendsignon = false; - } - } - } - - -// clear muzzle flashes - SV_CleanupEnts (); -} - - -/* -============================================================================== - -SERVER SPAWNING - -============================================================================== -*/ - -/* -================ -SV_ModelIndex - -================ -*/ -int SV_ModelIndex (const char *name) -{ - int i; - - if (!name || !name[0]) - return 0; - - for (i=0 ; i<MAX_MODELS && sv.model_precache[i] ; i++) - if (!strcmp(sv.model_precache[i], name)) - return i; - if (i==MAX_MODELS || !sv.model_precache[i]) - Sys_Error ("SV_ModelIndex: model %s not precached", name); - return i; -} - -/* -================ -SV_CreateBaseline - -================ -*/ -void SV_CreateBaseline (void) -{ - int i; - edict_t *svent; - int entnum; - - for (entnum = 0; entnum < sv.num_edicts ; entnum++) - { - // get the current server version - svent = EDICT_NUM(entnum); - if (svent->free) - continue; - if (entnum > svs.maxclients && !svent->u.v.modelindex) - continue; - - // - // create entity baseline - // - VectorCopy (svent->u.v.origin, svent->baseline.origin); - VectorCopy (svent->u.v.angles, svent->baseline.angles); - svent->baseline.frame = (int) svent->u.v.frame; - svent->baseline.skin = (int) svent->u.v.skin; - if (entnum > 0 && entnum <= svs.maxclients) - { - svent->baseline.colormap = entnum; - svent->baseline.modelindex = SV_ModelIndex("progs/player.mdl"); - } - else - { - svent->baseline.colormap = 0; - svent->baseline.modelindex = - SV_ModelIndex(pr_strings + svent->u.v.model); - } - - // - // add to the message - // - MSG_WriteByte (&sv.signon,svc_spawnbaseline); - MSG_WriteShort (&sv.signon,entnum); - - MSG_WriteByte (&sv.signon, svent->baseline.modelindex); - MSG_WriteByte (&sv.signon, svent->baseline.frame); - MSG_WriteByte (&sv.signon, svent->baseline.colormap); - MSG_WriteByte (&sv.signon, svent->baseline.skin); - for (i=0 ; i<3 ; i++) - { - MSG_WriteCoord(&sv.signon, svent->baseline.origin[i]); - MSG_WriteAngle(&sv.signon, svent->baseline.angles[i]); - } - } -} - - -/* -================ -SV_SendReconnect - -Tell all the clients that the server is changing levels -================ -*/ -void SV_SendReconnect (void) -{ - char data[128]; - sizebuf_t msg; - - msg.data = (byte*) data; - msg.cursize = 0; - msg.maxsize = sizeof(data); - - MSG_WriteChar (&msg, svc_stufftext); - MSG_WriteString (&msg, "reconnect\n"); - NET_SendToAll (&msg, 5); - - if (cls.state != ca_dedicated) -#ifdef QUAKE2 - Cbuf_InsertText ("reconnect\n"); -#else - Cmd_ExecuteString2 ("reconnect\n", src_command); -#endif -} - - -/* -================ -SV_SaveSpawnparms - -Grabs the current state of each client for saving across the -transition to another level -================ -*/ -void SV_SaveSpawnparms (void) -{ - int i, j; - - svs.serverflags = (int) pr_global_struct->serverflags; - - for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++) - { - if (!host_client->active) - continue; - - // call the progs to get default spawn parms for the new client - pr_global_struct->self = EDICT_TO_PROG(host_client->edict); - PR_ExecuteProgram (pr_global_struct->SetChangeParms); - for (j=0 ; j<NUM_SPAWN_PARMS ; j++) - host_client->spawn_parms[j] = (&pr_global_struct->parm1)[j]; - } -} - - -/* -================ -SV_SpawnServer - -This is called at the start of each level -================ -*/ -extern float scr_centertime_off; - -#ifdef QUAKE2 -void SV_SpawnServer (char *server, char *startspot) -#else -void SV_SpawnServer (char *server) -#endif -{ - edict_t *ent; - int i; - - // let's not have any servers with no name - if (hostname.string[0] == 0) - Cvar_Set ("hostname", "UNNAMED"); - scr_centertime_off = 0; - - Con_DPrintf ("SpawnServer: %s\n",server); - svs.changelevel_issued = false; // now safe to issue another - -// -// tell all connected clients that we are going to a new level -// - if (sv.active) - { - SV_SendReconnect (); - } - -// -// make cvars consistant -// - if (coop.value) - Cvar_SetValue ("deathmatch", 0); - current_skill = (int)(skill.value + 0.5); - if (current_skill < 0) - current_skill = 0; - if (current_skill > 3) - current_skill = 3; - - Cvar_SetValue ("skill", (float)current_skill); - -// -// set up the new server -// - Host_ClearMemory (); - - memset (&sv, 0, sizeof(sv)); - - strcpy (sv.name, server); -#ifdef QUAKE2 - if (startspot) - strcpy(sv.startspot, startspot); -#endif - -// load progs to get entity field count - PR_LoadProgs (); - -// allocate server memory - sv.max_edicts = MAX_EDICTS; - - sv.edicts = (edict_t*) Hunk_AllocName (sv.max_edicts*pr_edict_size, "edicts"); - - sv.datagram.maxsize = sizeof(sv.datagram_buf); - sv.datagram.cursize = 0; - sv.datagram.data = sv.datagram_buf; - - sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf); - sv.reliable_datagram.cursize = 0; - sv.reliable_datagram.data = sv.reliable_datagram_buf; - - sv.signon.maxsize = sizeof(sv.signon_buf); - sv.signon.cursize = 0; - sv.signon.data = sv.signon_buf; - -// leave slots at start for clients only - sv.num_edicts = svs.maxclients+1; - for (i=0 ; i<svs.maxclients ; i++) - { - ent = EDICT_NUM(i+1); - svs.clients[i].edict = ent; - } - - sv.state = ss_loading; - sv.paused = false; - - sv.time = 1.0; - - strcpy (sv.name, server); - sprintf (sv.modelname,"maps/%s.bsp", server); - sv.worldmodel = Mod_ForName (sv.modelname, false); - if (!sv.worldmodel) - { - Con_Printf ("Couldn't spawn server %s\n", sv.modelname); - sv.active = false; - return; - } - sv.models[1] = sv.worldmodel; - -// -// clear world interaction links -// - SV_ClearWorld (); - - sv.sound_precache[0] = pr_strings; - - sv.model_precache[0] = pr_strings; - sv.model_precache[1] = sv.modelname; - for (i=1 ; i<sv.worldmodel->numsubmodels ; i++) - { - sv.model_precache[1+i] = localmodels[i]; - sv.models[i+1] = Mod_ForName (localmodels[i], false); - } - -// -// load the rest of the entities -// - ent = EDICT_NUM(0); - memset (&ent->u.v, 0, progs->entityfields * 4); - ent->free = false; - ent->u.v.model = sv.worldmodel->name - pr_strings; - ent->u.v.modelindex = 1; // world model - ent->u.v.solid = SOLID_BSP; - ent->u.v.movetype = MOVETYPE_PUSH; - - if (coop.value) - pr_global_struct->coop = coop.value; - else - pr_global_struct->deathmatch = deathmatch.value; - - pr_global_struct->mapname = sv.name - pr_strings; -#ifdef QUAKE2 - pr_global_struct->startspot = sv.startspot - pr_strings; -#endif - -// serverflags are for cross level information (sigils) - pr_global_struct->serverflags = svs.serverflags; - - ED_LoadFromFile (sv.worldmodel->entities); - - sv.active = true; - -// all setup is completed, any further precache statements are errors - sv.state = ss_active; - -// run two frames to allow everything to settle - host_frametime = 0.1; - SV_Physics (); - SV_Physics (); - -// create a baseline for more efficient communications - SV_CreateBaseline (); - -// send serverinfo to all connected clients - for (i=0,host_client = svs.clients ; i<svs.maxclients ; i++, host_client++) - if (host_client->active) - SV_SendServerinfo (host_client); - - Con_DPrintf ("Server spawned.\n"); -} - |