📄 sv_user.c
字号:
/*
Copyright (C) 1997-2001 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_user.c -- server code for moving users
#include "server.h"
edict_t *sv_player;
/*
============================================================
USER STRINGCMD EXECUTION
sv_client and sv_player will be valid.
============================================================
*/
/*
==================
SV_BeginDemoServer
==================
*/
void SV_BeginDemoserver (void)
{
char name[MAX_OSPATH];
Com_sprintf (name, sizeof(name), "demos/%s", sv.name);
FS_FOpenFile (name, &sv.demofile);
if (!sv.demofile)
Com_Error (ERR_DROP, "Couldn't open %s\n", name);
}
/*
================
SV_New_f
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_New_f (void)
{
char *gamedir;
int playernum;
edict_t *ent;
Com_DPrintf ("New() from %s\n", sv_client->name);
if (sv_client->state != cs_connected)
{
Com_Printf ("New not valid -- already spawned\n");
return;
}
// demo servers just dump the file message
if (sv.state == ss_demo)
{
SV_BeginDemoserver ();
return;
}
//
// serverdata needs to go over for all types of servers
// to make sure the protocol is right, and to set the gamedir
//
gamedir = Cvar_VariableString ("gamedir");
// send the serverdata
MSG_WriteByte (&sv_client->netchan.message, svc_serverdata);
MSG_WriteLong (&sv_client->netchan.message, PROTOCOL_VERSION);
MSG_WriteLong (&sv_client->netchan.message, svs.spawncount);
MSG_WriteByte (&sv_client->netchan.message, sv.attractloop);
MSG_WriteString (&sv_client->netchan.message, gamedir);
if (sv.state == ss_cinematic || sv.state == ss_pic)
playernum = -1;
else
playernum = sv_client - svs.clients;
MSG_WriteShort (&sv_client->netchan.message, playernum);
// send full levelname
MSG_WriteString (&sv_client->netchan.message, sv.configstrings[CS_NAME]);
//
// game server
//
if (sv.state == ss_game)
{
// set up the entity for the client
ent = EDICT_NUM(playernum+1);
ent->s.number = playernum+1;
sv_client->edict = ent;
memset (&sv_client->lastcmd, 0, sizeof(sv_client->lastcmd));
// begin fetching configstrings
MSG_WriteByte (&sv_client->netchan.message, svc_stufftext);
MSG_WriteString (&sv_client->netchan.message, va("cmd configstrings %i 0\n",svs.spawncount) );
}
}
/*
==================
SV_Configstrings_f
==================
*/
void SV_Configstrings_f (void)
{
int start;
Com_DPrintf ("Configstrings() from %s\n", sv_client->name);
if (sv_client->state != cs_connected)
{
Com_Printf ("configstrings not valid -- already spawned\n");
return;
}
// handle the case of a level changing while a client was connecting
if ( atoi(Cmd_Argv(1)) != svs.spawncount )
{
Com_Printf ("SV_Configstrings_f from different level\n");
SV_New_f ();
return;
}
start = atoi(Cmd_Argv(2));
// write a packet full of data
while ( sv_client->netchan.message.cursize < MAX_MSGLEN/2
&& start < MAX_CONFIGSTRINGS)
{
if (sv.configstrings[start][0])
{
MSG_WriteByte (&sv_client->netchan.message, svc_configstring);
MSG_WriteShort (&sv_client->netchan.message, start);
MSG_WriteString (&sv_client->netchan.message, sv.configstrings[start]);
}
start++;
}
// send next command
if (start == MAX_CONFIGSTRINGS)
{
MSG_WriteByte (&sv_client->netchan.message, svc_stufftext);
MSG_WriteString (&sv_client->netchan.message, va("cmd baselines %i 0\n",svs.spawncount) );
}
else
{
MSG_WriteByte (&sv_client->netchan.message, svc_stufftext);
MSG_WriteString (&sv_client->netchan.message, va("cmd configstrings %i %i\n",svs.spawncount, start) );
}
}
/*
==================
SV_Baselines_f
==================
*/
void SV_Baselines_f (void)
{
int start;
entity_state_t nullstate;
entity_state_t *base;
Com_DPrintf ("Baselines() from %s\n", sv_client->name);
if (sv_client->state != cs_connected)
{
Com_Printf ("baselines not valid -- already spawned\n");
return;
}
// handle the case of a level changing while a client was connecting
if ( atoi(Cmd_Argv(1)) != svs.spawncount )
{
Com_Printf ("SV_Baselines_f from different level\n");
SV_New_f ();
return;
}
start = atoi(Cmd_Argv(2));
memset (&nullstate, 0, sizeof(nullstate));
// write a packet full of data
while ( sv_client->netchan.message.cursize < MAX_MSGLEN/2
&& start < MAX_EDICTS)
{
base = &sv.baselines[start];
if (base->modelindex || base->sound || base->effects)
{
MSG_WriteByte (&sv_client->netchan.message, svc_spawnbaseline);
MSG_WriteDeltaEntity (&nullstate, base, &sv_client->netchan.message, true, true);
}
start++;
}
// send next command
if (start == MAX_EDICTS)
{
MSG_WriteByte (&sv_client->netchan.message, svc_stufftext);
MSG_WriteString (&sv_client->netchan.message, va("precache %i\n", svs.spawncount) );
}
else
{
MSG_WriteByte (&sv_client->netchan.message, svc_stufftext);
MSG_WriteString (&sv_client->netchan.message, va("cmd baselines %i %i\n",svs.spawncount, start) );
}
}
/*
==================
SV_Begin_f
==================
*/
void SV_Begin_f (void)
{
Com_DPrintf ("Begin() from %s\n", sv_client->name);
// handle the case of a level changing while a client was connecting
if ( atoi(Cmd_Argv(1)) != svs.spawncount )
{
Com_Printf ("SV_Begin_f from different level\n");
SV_New_f ();
return;
}
sv_client->state = cs_spawned;
// call the game begin function
ge->ClientBegin (sv_player);
Cbuf_InsertFromDefer ();
}
//=============================================================================
/*
==================
SV_NextDownload_f
==================
*/
void SV_NextDownload_f (void)
{
int r;
int percent;
int size;
if (!sv_client->download)
return;
r = sv_client->downloadsize - sv_client->downloadcount;
if (r > 1024)
r = 1024;
MSG_WriteByte (&sv_client->netchan.message, svc_download);
MSG_WriteShort (&sv_client->netchan.message, r);
sv_client->downloadcount += r;
size = sv_client->downloadsize;
if (!size)
size = 1;
percent = sv_client->downloadcount*100/size;
MSG_WriteByte (&sv_client->netchan.message, percent);
SZ_Write (&sv_client->netchan.message,
sv_client->download + sv_client->downloadcount - r, r);
if (sv_client->downloadcount != sv_client->downloadsize)
return;
FS_FreeFile (sv_client->download);
sv_client->download = NULL;
}
/*
==================
SV_BeginDownload_f
==================
*/
void SV_BeginDownload_f(void)
{
char *name;
extern cvar_t *allow_download;
extern cvar_t *allow_download_players;
extern cvar_t *allow_download_models;
extern cvar_t *allow_download_sounds;
extern cvar_t *allow_download_maps;
extern int file_from_pak; // ZOID did file come from pak?
int offset = 0;
name = Cmd_Argv(1);
if (Cmd_Argc() > 2)
offset = atoi(Cmd_Argv(2)); // downloaded offset
// hacked by zoid to allow more conrol over download
// first off, no .. or global allow check
if (strstr (name, "..") || !allow_download->value
// leading dot is no good
|| *name == '.'
// leading slash bad as well, must be in subdir
|| *name == '/'
// next up, skin check
|| (strncmp(name, "players/", 6) == 0 && !allow_download_players->value)
// now models
|| (strncmp(name, "models/", 6) == 0 && !allow_download_models->value)
// now sounds
|| (strncmp(name, "sound/", 6) == 0 && !allow_download_sounds->value)
// now maps (note special case for maps, must not be in pak)
|| (strncmp(name, "maps/", 6) == 0 && !allow_download_maps->value)
// MUST be in a subdirectory
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -