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

📄 sv_user.pas

📁 雷神之锤2(Quake2)Delphi源码
💻 PAS
📖 第 1 页 / 共 2 页
字号:
unit sv_user;

{----------------------------------------------------------------------------}
{                                                                            }
{ File(s): sv_user.c                                                         }
{                                                                            }
{ Initial conversion by : Scott Price (scott.price@totalise.co.uk)           }
{ Initial conversion on : 23-Feb-2002                                        }
{                                                                            }
{ This File contains part of convertion of Quake2 source to ObjectPascal.    }
{ More information about this project can be found at:                       }
{ http://www.sulaco.co.za/quake2/                                            }
{                                                                            }
{ 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.                       }
{                                                                            }
{----------------------------------------------------------------------------}
{ Updated on : 16-jul-2002                                                   }
{ Updated by : Sly                                                           }
{ - Fixed bad translation of SV_ExecuteUserCommand                           }
{                                                                            }
{----------------------------------------------------------------------------}
{ * Still dependent (to compile correctly) on:                               }
{----------------------------------------------------------------------------}
{ * TODO:                                                                    }
{----------------------------------------------------------------------------}
// 25.07.2002 Juha: Proof-readed this unit

interface



uses
  SysUtils,
  GameUnit,
  Server,
  sv_init;


const
  MAX_STRINGCMDS = 8;


type
  ucmd_t = packed record
    name: PChar;
    func: procedure;
  end;
  ucmd_p = ^ucmd_t;

// Global functions
procedure SV_Nextserver;
procedure SV_ExecuteClientMessage(cl: client_p);


// Functions for the local array
procedure SV_New_f;
procedure SV_Configstrings_f;
procedure SV_Baselines_f;
procedure SV_Begin_f;
procedure SV_Nextserver_f;
procedure SV_Disconnect_f;
procedure SV_ShowServerinfo_f;
procedure SV_BeginDownload_f;
procedure SV_NextDownload_f;

var
  sv_player: edict_p;

  ucmds: array[0..9] of ucmd_t = ( // auto issued
    (name: 'new'; func: SV_New_f),
    (name: 'configstrings'; func: SV_Configstrings_f),
    (name: 'baselines'; func: SV_Baselines_f),
    (name: 'begin'; func: SV_Begin_f),

    (name: 'nextserver'; func: SV_Nextserver_f),

    (name: 'disconnect'; func: SV_Disconnect_f),

    // issued by hand at client consoles
    (name: 'info'; func: SV_ShowServerinfo_f),

    (name: 'download'; func: SV_BeginDownload_f),
    (name: 'nextdl'; func: SV_NextDownload_f),

    (name: nil; func: nil) );

implementation

uses
  Files,
  Common,
  CVar,
  CPas,
  Cmd,
  net_chan,
  sv_main,
  sv_game,
  q_shared;


(* ============================================================

USER STRINGCMD EXECUTION

sv_client and sv_player will be valid.
============================================================ *)

(* ==================
SV_BeginDemoServer
================== *)
procedure SV_BeginDemoserver;
var
  name: array[0..MAX_OSPATH-1] of char;
begin
  Com_sprintf(name, SizeOf(name), 'demos/%s', [sv.name]);
  FS_FOpenFile(name, sv.demofile);
  if (sv.demofile = 0) then
    Com_Error(ERR_DROP, 'Couldn''t open %s'#10, [name]);
end;

(* ================
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.
================ *)
procedure SV_New_f;
var
  gamedir: PChar;
  playernum: Integer;
  ent: edict_p;
begin
  Com_DPrintf('New() from %s'#10, [sv_client^.name]);

  if (sv_client^.state <> cs_connected) then
  begin
    Com_Printf('New not valid -- already spawned'#10, []);
    Exit;
  end;

  { demo servers just dump the file message }
  if (sv.state = ss_demo) then
  begin
    SV_BeginDemoserver;
    Exit;
  end;

  { 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, Integer(svc_serverdata));
  MSG_WriteLong(sv_client^.netchan.message, PROTOCOL_VERSION);
  MSG_WriteLong(sv_client^.netchan.message, svs.spawncount);
  MSG_WriteByte(sv_client^.netchan.message, Integer(sv.attractloop));
  MSG_WriteString(sv_client^.netchan.message, gamedir);

  if (sv.state = ss_cinematic) OR (sv.state = ss_pic) then
    playernum := -1
  else
    playernum := (Cardinal(sv_client) - Cardinal(svs.clients)) div sizeof(client_t);

  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) then
  begin
    { set up the entity for the client }
    ent := EDICT_NUM(playernum + 1);
    ent^.s.number := playernum + 1;
    sv_client^.edict := ent;
    FillChar(sv_client^.lastcmd, SizeOf(sv_client^.lastcmd), 0);

    { begin fetching configstrings }
    MSG_WriteByte(sv_client^.netchan.message, Integer(svc_stufftext));
    MSG_WriteString(sv_client^.netchan.message, va('cmd configstrings %d 0'#10, [svs.spawncount]));
  end;
end;

(* ==================
SV_Configstrings_f
================== *)
procedure SV_Configstrings_f;
var
  start, iHalfMesLen: Integer;
begin
  Com_DPrintf('Configstrings() from %s'#10, [sv_client^.name]);

  if (sv_client^.state <> cs_connected) then
  begin
    Com_Printf('configstrings not valid -- already spawned'#10, []);
    Exit;
  end;

  { handle the case of a level changing while a client was connecting }
  if (StrToInt(Cmd_Argv(1)) <> svs.spawncount) then
  begin
    Com_Printf('SV_Configstrings_f from different level'#10, []);
    SV_New_f;
    Exit;
  end;

  start := StrToInt(Cmd_Argv(2));

  { write a packet full of data }

  iHalfMesLen := (MAX_MSGLEN div 2);
  while (sv_client^.netchan.message.cursize < iHalfMesLen) AND (start < MAX_CONFIGSTRINGS) do
  begin
    if (sv.configstrings[start][0] <> #0) then
    begin
      MSG_WriteByte(sv_client^.netchan.message, Integer(svc_configstring));
      MSG_WriteShort(sv_client^.netchan.message, start);
      MSG_WriteString(sv_client^.netchan.message, sv.configstrings[start]);
    end;

    Inc(start);
  end;

  { send next command }
  if (start = MAX_CONFIGSTRINGS) then
  begin
    MSG_WriteByte(sv_client^.netchan.message, Integer(svc_stufftext));
    MSG_WriteString(sv_client^.netchan.message, va('cmd baselines %d 0'#10, [svs.spawncount]));
  end
  else
  begin
    MSG_WriteByte(sv_client^.netchan.message, Integer(svc_stufftext));
    MSG_WriteString(sv_client^.netchan.message, va('cmd configstrings %d %d'#10, [svs.spawncount, start]));
  end;
end;

(* ==================
SV_Baselines_f
================== *)
procedure SV_Baselines_f;
var
  start, iHalfMesLen: Integer;
  nullstate: entity_state_t;
  base: entity_state_p;
begin
  Com_DPrintf('Baselines() from %s'#10, [sv_client^.name]);

  if (sv_client^.state <> cs_connected) then
  begin
    Com_Printf('baselines not valid -- already spawned'#10, []);
    Exit;
  end;

  { handle the case of a level changing while a client was connecting }
  if (StrToInt(Cmd_Argv(1)) <> svs.spawncount) then
  begin
    Com_Printf('SV_Baselines_f from different level'#10, []);
    SV_New_f;
    Exit;
  end;

  start := StrToInt(Cmd_Argv(2));

  FillChar(nullstate, SizeOf(nullstate), 0);

  { write a packet full of data }
  iHalfMesLen := (MAX_MSGLEN div 2);
  while (sv_client^.netchan.message.cursize < iHalfMesLen) AND (start < MAX_EDICTS) do
  begin
    base := @sv.baselines[start];
    if (base^.modelindex<>0) OR (base^.sound<>0) OR (base^.effects<>0) then
    begin
      MSG_WriteByte(sv_client^.netchan.message, Integer(svc_spawnbaseline));
      MSG_WriteDeltaEntity(nullstate, base^, sv_client^.netchan.message, true, true);
    end;

    Inc(start);
  end;

  { send next command }
  if (start = MAX_EDICTS) then
  begin
    MSG_WriteByte(sv_client^.netchan.message, Integer(svc_stufftext));
    MSG_WriteString(sv_client^.netchan.message, va('precache %d'#10, [svs.spawncount]));
  end
  else
  begin
    MSG_WriteByte(sv_client^.netchan.message, Integer(svc_stufftext));
    MSG_WriteString(sv_client^.netchan.message, va('cmd baselines %d %d'#10, [svs.spawncount, start]));
  end;
end;

(* ==================
SV_Begin_f
================== *)
procedure SV_Begin_f;
begin
  Com_DPrintf('Begin() from %s'#10, [sv_client^.name]);

  { handle the case of a level changing while a client was connecting }
  if (StrToInt(Cmd_Argv(1)) <> svs.spawncount) then
  begin
    Com_Printf('SV_Begin_f from different level'#10, []);
    SV_New_f;
    Exit;
  end;

  sv_client^.state := cs_spawned;

  { call the game begin function }
  ge^.ClientBegin(sv_player);

  Cbuf_InsertFromDefer;
end;

(* ==================
SV_NextDownload_f
================== *)
procedure SV_NextDownload_f;
var
  r, percent, size: Integer;
begin
  if (sv_client^.download = nil) then
     Exit;

  r := (sv_client^.downloadsize - sv_client^.downloadcount);
  if (r > 1024) then
    r := 1024;

  MSG_WriteByte(sv_client^.netchan.message, Integer(svc_download));
  MSG_WriteShort(sv_client^.netchan.message, r);

⌨️ 快捷键说明

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