⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sv_ccmds.pas

📁 雷神之锤2(Quake2)Delphi源码
💻 PAS
📖 第 1 页 / 共 2 页
字号:
      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 + -