📄 sv_ccmds.pas
字号:
while (i<maxclients.value) do begin
savedInuse^[i] := cl^.edict^.inuse;
cl^.edict^.inuse := false;
Inc(i);
Inc(cl);
End;
SV_WriteLevelFile ();
// we must restore these for clients to transfer over correctly
cl := client_p(svs.clients);
i := 0;
while (i < maxclients.value) do begin
cl^.edict^.inuse := savedInuse^[i];
inc(i);
inc(cl);
end;
free (savedInuse);
End;
End;
// start up the next map
SV_Map (false, Cmd_Argv(1), false );
// archive server state
strncpy (@svs.mapcmd, Cmd_Argv(1), sizeof(svs.mapcmd)-1);
// copy off the level to the autosave slot
if not (dedicated.value<>0) then
Begin
SV_WriteServerFile (true);
SV_CopySaveGame ('current', 'save0');
End;
End;
(*
==================================================
SV_Map_f
Goes directly to a given map without any savegame archiving.
For development work
==================================================
*)
procedure SV_Map_f (); cdecl;
var
map: pchar;
expanded: array[0..MAX_QPATH-1] of char;
begin
// if not a pcx, demo, or cinematic, check to make sure the level exists
map := Cmd_Argv(1);
if (not (strstr (map, '.')<>nil)) then
begin
Com_sprintf (expanded, sizeof(expanded), 'maps/%s.bsp', [map]);
if FS_LoadFile (expanded, nil) = -1 then
Begin
Com_Printf ('Can''t find %s'#10, [expanded]);
exit;
End;
End;
sv.state := ss_dead; // don't save current level when changing
SV_WipeSavegame('current');
SV_GameMap_f ();
End;
(*
==================================================
SAVEGAMES
==================================================
*)
(*
==================================================
SV_Loadgame_f
==================================================
*)
procedure SV_Loadgame_f (); cdecl;
var
name: array[0..MAX_OSPATH-1] of Char;
f: Integer;
dir: PChar;
begin
if (Cmd_Argc() <> 2) then
begin
Com_Printf ('USAGE: loadgame <directory>'#10, []);
exit;
end;
Com_Printf ('Loading game...'#10, []);
dir := Cmd_Argv(1);
if (strstr (dir, '..')<>nil) or (strstr (dir, '/')<>nil) or (strstr (dir, '\')<>nil) then
begin
Com_Printf ('Bad savedir.'#10, []);
end;
// make sure the server.ssv file exists
Com_sprintf (name, sizeof(name), '%s/save/%s/server.ssv', [FS_Gamedir(), Cmd_Argv(1)]);
f := FileOpen (name, fmOpenRead);
if (f = -1) then
Begin
Com_Printf ('No such savegame: %s'#10, [name]);
exit;
End;
FileClose (f);
SV_CopySaveGame (Cmd_Argv(1), 'current');
SV_ReadServerFile ();
// go to the map
sv.state := ss_dead; // don't save current level when changing
SV_Map (false, @svs.mapcmd, true);
end;
(*
==================================================
SV_Savegame_f
==================================================
*)
procedure SV_Savegame_f (); cdecl;
var
dir: pchar;
begin
if ( sv.state <> ss_game) then
begin
Com_Printf ('You must be in a game to save.'#10, []);
exit;
end;
if (Cmd_Argc() <> 2) then
begin
Com_Printf ('USAGE: savegame <directory>'#10, []);
exit;
end;
if (Cvar_VariableValue('deathmatch')<>0) then
begin
Com_Printf ('Can''t savegame in a deathmatch'#10, []);
exit;
end;
if not (strcmp (Cmd_Argv(1), 'current')<>0) then
begin
Com_Printf ('Can''t save to ''current'''#10, []);
exit;
end;
if (maxclients.value = 1) and (svs.clients^[0].edict^.client^.ps.stats[STAT_HEALTH] <= 0) then
begin
Com_Printf (#10'Can''t savegame while dead!'#10, []);
exit;
end;
dir := Cmd_Argv(1);
if (strstr (dir, '..')<>nil) or (strstr (dir, '/')<>nil) or (strstr (dir, '\')<>nil) then
begin
Com_Printf ('Bad savedir.'#10, []);
end;
Com_Printf ('Saving game...'#10, []);
// archive current level, including all client edicts.
// when the level is reloaded, they will be shells awaiting
// a connecting client
SV_WriteLevelFile ();
// save server state
SV_WriteServerFile (false);
// copy it off
SV_CopySaveGame ('current', dir);
Com_Printf ('Done.'#10, []);
End;
(*
==================================================
SV_Kick_f
Kick a user off of the server
==================================================
*)
procedure SV_Kick_f (); cdecl;
begin
if (not svs.initialized) then
begin
Com_Printf ('No server running.'#10, []);
exit;
end;
if (Cmd_Argc() <> 2) then
begin
Com_Printf ('Usage: kick <userid>'#10, []);
exit;
end;
if (not SV_SetPlayer ()) then
exit;
SV_BroadcastPrintf (PRINT_HIGH, '%s was kicked'#10, [sv_client^.name]);
// print directly, because the dropped client won't get the
// SV_BroadcastPrintf message
SV_ClientPrintf (sv_client, PRINT_HIGH, 'You were kicked from the game'#10, []);
SV_DropClient (sv_client);
sv_client^.lastmessage := svs.realtime; // min case there is a funny zombie
end;
(*
==================================================
SV_Status_f
==================================================
*)
procedure SV_Status_f; cdecl;
Var
i, j, l: integer;
cl: client_p;
s: pchar;
ping: integer;
label
continue_;
begin
if (svs.clients = nil) then
begin
Com_Printf ('No server running.'#10, []);
exit;
end;
Com_Printf ('map : %s'#10, [sv.name]);
Com_Printf ('num score ping name lastmsg address qport '#10, []);
Com_Printf ('--- ----- ---- --------------- ------- --------------------- ------'#10, []);
i := 0;
cl := client_p(svs.clients);
while (i<maxclients.value) do begin
if (Integer(cl.state) = 0) then
goto continue_;
Com_Printf ('%3i ', [i]);
Com_Printf ('%5i ', [cl^.edict^.client^.ps.stats[STAT_FRAGS]]);
if (cl^.state = cs_connected) then
Com_Printf ('CNCT ', [])
else if (cl^.state = cs_zombie) then
Com_Printf ('ZMBI ', [])
else
begin
if cl^.ping < 9999 then
ping := cl^.ping
else
ping := 9999;
Com_Printf ('%4i ', [ping]);
end;
Com_Printf ('%s', [cl^.name]);
l := 16 - strlen(cl.name);
for j := 0 to l-1 do
Com_Printf (' ');
Com_Printf ('%7i ', [svs.realtime - cl.lastmessage] );
s := NET_AdrToString ( cl.netchan.remote_address);
Com_Printf ('%s', [s]);
l := 22 - strlen(s);
for j :=0 to l-1 do
Com_Printf (' ');
Com_Printf ('%5i', [cl.netchan.qport]);
Com_Printf (#10);
continue_:
Inc(i);
Inc(cl);
end;
Com_Printf (#10);
end;
(*
==================================================
SV_ConSay_f
==================================================
*)
Procedure SV_ConSay_f; cdecl;
var
client: client_p;
j: integer;
p: pchar;
text: array[0..1024-1] of char;
label
continue_;
begin
if (Cmd_Argc () < 2) then
exit;
strcpy (text, 'console: ');
p := Cmd_Args();
if (p^ = '"') then
begin
Inc(p);
p[strlen(p)-1] := #0;
end;
strcat(text, p);
j := 0;
client := client_p(svs.clients);
while (j < maxclients.value) do
begin
if (client^.state <> cs_spawned) then
goto continue_;
SV_ClientPrintf(client, PRINT_CHAT, '%s'#10, [text]);
continue_:
Inc(j);
Inc(client);
end;
end;
(*
==================================================
SV_Heartbeat_f
==================================================
*)
procedure SV_Heartbeat_f; cdecl;
begin
svs.last_heartbeat := -9999999;
end;
(*
==================================================
SV_Serverinfo_f
Examine or change the serverinfo string
==================================================
*)
procedure SV_Serverinfo_f; cdecl;
begin
Com_Printf ('Server info settings:'#10);
Info_Print (Cvar_Serverinfo_());
end;
(*
==================================================
SV_DumpUser_f
Examine all a users info strings
==================================================
*)
Procedure SV_DumpUser_f; cdecl;
Begin
if (Cmd_Argc() <> 2) then
Begin
Com_Printf ('Usage: info <userid>'#10);
exit;
End;
if (not SV_SetPlayer ()) then
exit;
Com_Printf ('userinfo'#10);
Com_Printf ('--------'#10);
Info_Print (sv_client.userinfo);
End;
(*
==================================================
SV_ServerRecord_f
Begins server demo recording. Every entity and every message will be
recorded, but no playerinfo will be stored. Primarily for demo merging.
==================================================
*)
procedure SV_ServerRecord_f; cdecl;
var
name: array[0..MAX_OSPATH-1] of char;
buf_data: array[0..32768-1] of char;
buf: sizebuf_t;
len: integer;
i: integer;
Begin
if (Cmd_Argc() <> 2) then
Begin
Com_Printf ('serverrecord <demoname>'#10);
exit;
End;
if (svs.demofile>0) then
Begin
Com_Printf ('Already recording.'#10);
exit;
End;
if (sv.state <> ss_game) then
Begin
Com_Printf ('You must be in a level to record.'#10);
exit;
End;
//
// open the demo file
//
Com_sprintf (name, sizeof(name), '%s/demos/%s.dm2', [FS_Gamedir(), Cmd_Argv(1)]);
Com_Printf ('recording to %s.'#10, [name]);
FS_CreatePath (name);
svs.demofile := FileOpen (name, fmOpenReadWrite);
if (svs.demofile = -1) then
Begin
Com_Printf ('ERROR: couldn''t open.'#10);
exit;
End;
// setup a buffer to catch all multicasts
SZ_Init (svs.demo_multicast, @svs.demo_multicast_buf, sizeof(svs.demo_multicast_buf));
//
// write a single giant fake message with all the startup info
//
SZ_Init (buf, @buf_data, sizeof(buf_data));
//
// serverdata needs to go over for all types of servers
// to make sure the protocol is right, and to set the gamedir
//
// send the serverdata
MSG_WriteByte (buf, Integer(svc_serverdata));
MSG_WriteLong (buf, PROTOCOL_VERSION);
MSG_WriteLong (buf, svs.spawncount);
// 2 means server demo
MSG_WriteByte (buf, 2); // demos are always attract loops
MSG_WriteString (buf, Cvar_VariableString ('gamedir'));
MSG_WriteShort (buf, -1);
// send full levelname
MSG_WriteString (buf, sv.configstrings[CS_NAME]);
for i := 0 to MAX_CONFIGSTRINGS-1 do
begin
if (sv.configstrings[i,0] <> #0) then
begin
MSG_WriteByte (buf, Integer(svc_configstring));
MSG_WriteShort (buf, i);
MSG_WriteString (buf, sv.configstrings[i]);
end;
end;
// write it to the demo file
Com_DPrintf ('signon message length: %i'#10, [buf.cursize]);
len := LittleLong (buf.cursize);
FileWrite (svs.demofile, len, 4);
FileWrite (svs.demofile, buf.data^, buf.cursize);
// the rest of the demo file will be individual frames
End;
(*
==================================================
SV_ServerStop_f
Ends server demo recording
==================================================
*)
Procedure SV_ServerStop_f; cdecl;
Begin
if (svs.demofile <= 0) then
Begin
Com_Printf ('Not doing a serverrecord.'#10);
exit;
End;
FileClose (svs.demofile);
svs.demofile := 0;
Com_Printf ('Recording completed.'#10);
End;
(*
==================================================
SV_KillServer_f
Kick everyone off, possibly in preparation for a new game
==================================================*)
Procedure SV_KillServer_f; cdecl;
Begin
if (not svs.initialized) then
exit;
SV_Shutdown ('Server was killed.'#10, false);
NET_Config ( false ); // close network sockets
End;
(*
==================================================
SV_ServerCommand_f
Let the game dll handle a command
==================================================
*)
Procedure SV_ServerCommand_f (); cdecl;
Begin
if (ge = nil) then
Begin
Com_Printf ('No game loaded.'#10);
exit;
End;
ge.ServerCommand();
End;
(*
==================================================
SV_InitOperatorCommands
==================================================
*)
Procedure SV_InitOperatorCommands ();
Begin
Cmd_AddCommand ('heartbeat', SV_Heartbeat_f);
Cmd_AddCommand ('kick', SV_Kick_f);
Cmd_AddCommand ('status', SV_Status_f);
Cmd_AddCommand ('serverinfo', SV_Serverinfo_f);
Cmd_AddCommand ('dumpuser', SV_DumpUser_f);
Cmd_AddCommand ('map', SV_Map_f);
Cmd_AddCommand ('demomap', SV_DemoMap_f);
Cmd_AddCommand ('gamemap', SV_GameMap_f);
Cmd_AddCommand ('setmaster', SV_SetMaster_f);
if ( dedicated.value<>0 ) then
Cmd_AddCommand ('say', SV_ConSay_f);
Cmd_AddCommand ('serverrecord', SV_ServerRecord_f);
Cmd_AddCommand ('serverstop', SV_ServerStop_f);
Cmd_AddCommand ('save', SV_Savegame_f);
Cmd_AddCommand ('load', SV_Loadgame_f);
Cmd_AddCommand ('killserver', SV_KillServer_f);
Cmd_AddCommand ('sv', SV_ServerCommand_f);
End;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -