sv_main.c

来自「quake1 dos源代码最新版本」· C语言 代码 · 共 1,327 行 · 第 1/3 页

C
1,327
字号
/*
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

// 2001-09-20 Configurable entity limits by Maddes  start
cvar_t	*sv_entities;
cvar_t	*sv_entities_static;
cvar_t	*sv_entities_temp;
// 2001-09-20 Configurable entity limits by Maddes  end

cvar_t	*sv_compatibility;	// 2001-12-24 Keeping full backwards compatibility by Maddes

//============================================================================

/*
===============
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;

	sv_maxvelocity = Cvar_Get ("sv_maxvelocity", "2000", CVAR_ORIGINAL);
	sv_gravity = Cvar_Get ("sv_gravity", "800", CVAR_NOTIFY|CVAR_SERVERINFO|CVAR_ORIGINAL);
	sv_friction = Cvar_Get ("sv_friction", "4", CVAR_NOTIFY|CVAR_SERVERINFO|CVAR_ORIGINAL);
	sv_edgefriction = Cvar_Get ("edgefriction", "2", CVAR_ORIGINAL);
	sv_stopspeed = Cvar_Get ("sv_stopspeed", "100", CVAR_ORIGINAL);
	sv_maxspeed = Cvar_Get ("sv_maxspeed", "320", CVAR_NOTIFY|CVAR_SERVERINFO|CVAR_ORIGINAL);
	sv_accelerate = Cvar_Get ("sv_accelerate", "10", CVAR_ORIGINAL);
	sv_idealpitchscale = Cvar_Get ("sv_idealpitchscale", "0.8", CVAR_ORIGINAL);
	sv_aim = Cvar_Get ("sv_aim", "0.93", CVAR_ORIGINAL);
	sv_nostep = Cvar_Get ("sv_nostep", "0", CVAR_ORIGINAL);
// 2001-09-20 Configurable entity limits by Maddes  start
	sv_entities = Cvar_Get ("sv_entities", "0", CVAR_NONE);
	Cvar_SetRangecheck (sv_entities, Cvar_RangecheckInt, MIN_EDICTS, MAX_EDICTS);
	Cvar_Set(sv_entities, sv_entities->string);	// do rangecheck

	sv_entities_static = Cvar_Get ("sv_entities_static", "0", CVAR_NONE);
	Cvar_SetRangecheck (sv_entities_static, Cvar_RangecheckInt, MIN_STATIC_ENTITIES, MAX_EDICTS);
	Cvar_Set(sv_entities_static, sv_entities_static->string);	// do rangecheck

	sv_entities_temp = Cvar_Get ("sv_entities_temp", "0", CVAR_NONE);
	Cvar_SetRangecheck (sv_entities_temp, Cvar_RangecheckInt, MIN_TEMP_ENTITIES, MAX_EDICTS);
	Cvar_Set(sv_entities_temp, sv_entities_temp->string);	// do rangecheck
// 2001-09-20 Configurable entity limits by Maddes  end

// 2001-12-24 Keeping full backwards compatibility by Maddes  start
	sv_compatibility = Cvar_Get ("sv_compatibility", "0", CVAR_NONE);
	Cvar_SetRangecheck (sv_compatibility, Cvar_RangecheckBool, 0, 1);
	Cvar_SetDescription (sv_compatibility, "When set to 1, this server will not reply on enhanced client requests and will not allow any NVS enhanced messages (precise client aiming, etc.). If you just want to record demos that shall run on all Quake executables, then use CL_COMPATIBILITY instead of SV_COMPATIBILITY.");
	Cvar_Set(sv_compatibility, sv_compatibility->string);	// do rangecheck
// 2001-12-24 Keeping full backwards compatibility by Maddes  end

	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;

// 2000-05-02 NVS SVC_particle by Maddes  start
/*
	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]);
*/
	NVS_InitSVCMsg(MSG_BROADCAST, svc_particle, 0, NULL);
	NVS_WriteByte (MSG_BROADCAST, svc_particle, NULL);
	NVS_WriteCoord (MSG_BROADCAST, org[0], NULL);
	NVS_WriteCoord (MSG_BROADCAST, org[1], NULL);
	NVS_WriteCoord (MSG_BROADCAST, org[2], NULL);
// 2000-05-02 NVS SVC_particle by Maddes  end
	for (i=0 ; i<3 ; i++)
	{
		v = dir[i]*16;
		if (v > 127)
			v = 127;
		else if (v < -128)
			v = -128;
// 2000-05-02 NVS SVC_particle by Maddes  start
//		MSG_WriteChar (&sv.datagram, v);
		NVS_WriteChar (MSG_BROADCAST, v, NULL);
// 2000-05-02 NVS SVC_particle by Maddes  end
	}
// 2000-05-02 NVS SVC_particle by Maddes  start
/*
	MSG_WriteByte (&sv.datagram, count);
	MSG_WriteByte (&sv.datagram, color);
*/
	NVS_WriteByte (MSG_BROADCAST, count, NULL);
	NVS_WriteByte (MSG_BROADCAST, color, NULL);
// 2000-05-02 NVS SVC_particle by Maddes  end
}

/*
==================
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
already 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, 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, attenuation*64);
	MSG_WriteShort (&sv.datagram, channel);
	MSG_WriteByte (&sv.datagram, sound_num);
	for (i=0 ; i<3 ; i++)
		MSG_WriteCoord (&sv.datagram, entity->v.origin[i]+0.5*(entity->v.mins[i]+entity->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)\n", 2, VERSION, pr_crc);	// 2000-01-08 Missing linefeeds fix by Maddes
	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, pr_strings+sv.edicts->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, sv.edicts->v.sounds);
	MSG_WriteByte (&client->message, sv.edicts->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

// 2000-05-02 NVS SVC by Maddes  start
	SZ_Clear(&client->message);

	client->datagram.data = client->datagram_buf;
	client->datagram.maxsize = sizeof(client->datagram_buf);
	SZ_Clear(&client->datagram);

	client->nvs_msgconversion = NULL;
	client->nvs_msgignore = true;		// safety first
// 2000-05-02 NVS SVC by Maddes  end

// 2000-04-30 NVS HANDSHAKE SRV<->CL by Maddes  start
	client->nvs_cmax = 0;
	client->nvs_cclc = 0;
	client->nvs_csvc = 0;
// 2000-04-30 NVS HANDSHAKE SRV<->CL by Maddes  end

#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)
			{

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?