📄 cl_parse.pas
字号:
{$ALIGN ON}{$MINENUMSIZE 4}
{----------------------------------------------------------------------------}
{ }
{ File(s): cl_parse }
{ Content: parse a message received from the server }
{ }
{ Initial conversion by : Ter Roshak }
{ Initial conversion on : - }
{ }
{ 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. }
{ }
{----------------------------------------------------------------------------}
// cl_parse.c -- parse a message received from the server
unit cl_parse;
interface
uses
q_shared,
client;
const
svc_strings: array[0..255] of PChar =
(
'svc_bad',
'svc_muzzleflash',
'svc_muzzlflash2',
'svc_temp_entity',
'svc_layout',
'svc_inventory',
'svc_nop',
'svc_disconnect',
'svc_reconnect',
'svc_sound',
'svc_print',
'svc_stufftext',
'svc_serverdata',
'svc_configstring',
'svc_spawnbaseline',
'svc_centerprint',
'svc_download',
'svc_playerinfo',
'svc_packetentities',
'svc_deltapacketentities',
'svc_frame',
nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
nil, nil, nil, nil, nil
);
procedure CL_ParseClientinfo(player: Integer);
procedure CL_LoadClientinfo(ci: clientinfo_p; s: pchar);
procedure CL_ParseServerMessage();
procedure CL_RegisterSounds();
function CL_CheckOrDownloadFile(filename: pchar): qboolean;
procedure CL_Download_f(); cdecl;
procedure SHOWNET(s: pchar);
implementation
uses
cl_inv,
cl_cin,
cl_main,
cl_tent,
cl_ents,
cl_view,
cl_fx,
cl_scrn,
{$IFDEF WIN32}
cd_win,
sys_win,
vid_dll,
{$ELSE}
cd_sdl,
sys_linux,
vid_so,
{$ENDIF}
net_chan,
SysUtils,
snd_dma,
Files,
Common,
Cmd,
Console,
CModel,
CVar,
CPas;
//=============================================================================
procedure CL_DownloadFileName(dest: pchar; destlen: integer; fn: pchar);
begin
if strncmp(fn, 'players', 7) = 0 then
Com_sprintf(dest, destlen, '%s/%s', [BASEDIRNAME, fn])
else
Com_sprintf(dest, destlen, '%s/%s', [FS_Gamedir(), fn]);
end;
{*
===============
CL_CheckOrDownloadFile
Returns true if the file exists, otherwise it attempts
to start a download from the server.
===============
*}
function CL_CheckOrDownloadFile(filename: pchar): qboolean;
var
fp: integer;
name: array[0..MAX_OSPATH - 1] of char;
len: Integer;
begin
if (strstr(filename, '..') <> nil) then
begin
Com_Printf('Refusing to download a path with ..'#10, []);
Result := True;
exit;
end;
if (FS_LoadFile(filename, nil) <> -1) then
begin
// it exists, no need to download
Result := True;
exit;
end;
strcpy(cls.downloadname, filename);
// download to a temp name, and only rename
// to the real name when done, so if interrupted
// a runt file wont be left
COM_StripExtension(cls.downloadname, cls.downloadtempname);
strcat(cls.downloadtempname, '.tmp');
//ZOID
// check to see if we already have a tmp for this file, if so, try to resume
// open the file if not opened yet
CL_DownloadFileName(name, sizeof(name), cls.downloadtempname);
// FS_CreatePath (name);
fp := FileOpen(name, fmOpenReadWrite);
if (fp <> -1) then
begin // it exists
len := FileSeek(fp, 0, 2);
cls.download := fp;
// give the server an offset to start the download
Com_Printf('Resuming %s'#10, [cls.downloadname]);
MSG_WriteByte(cls.netchan.message, Integer(clc_stringcmd));
MSG_WriteString(cls.netchan.message,
va('download %s %d', [cls.downloadname, len]));
end
else
begin
Com_Printf('Downloading %s'#10, [cls.downloadname]);
MSG_WriteByte(cls.netchan.message, Integer(clc_stringcmd));
MSG_WriteString(cls.netchan.message,
va('download %s', [cls.downloadname]));
end;
Inc(cls.downloadnumber);
Result := false;
end;
{*
===============
CL_Download_f
Request a download from the server
===============
*}
procedure CL_Download_f();
var
filename: array[0..MAX_OSPATH - 1] of char;
begin
if (Cmd_Argc() <> 2) then
begin
Com_Printf('Usage: download <filename>'#10);
exit;
end;
Com_sprintf(filename, sizeof(filename), '%s', [Cmd_Argv(1)]);
if (strstr(filename, '..') <> nil) then
begin
Com_Printf('Refusing to download a path with ..'#10);
exit;
end;
if (FS_LoadFile(filename, nil) <> -1) then
begin
// it exists, no need to download
Com_Printf('File already exists.'#10);
exit;
end;
strcpy(cls.downloadname, filename);
Com_Printf('Downloading %s'#10, [cls.downloadname]);
// download to a temp name, and only rename
// to the real name when done, so if interrupted
// a runt file wont be left
COM_StripExtension(cls.downloadname, cls.downloadtempname);
strcat(cls.downloadtempname, '.tmp');
MSG_WriteByte(cls.netchan.message, Integer(clc_stringcmd));
MSG_WriteString(cls.netchan.message,
va('download %s', [cls.downloadname]));
Inc(cls.downloadnumber);
end;
{*
======================
CL_RegisterSounds
======================
*}
procedure CL_RegisterSounds();
var
i: integer;
begin
S_BeginRegistration();
CL_RegisterTEntSounds();
for i := 1 to MAX_SOUNDS - 1 do
begin
if (cl.configstrings[CS_SOUNDS + i][0] = #0) then
break;
cl.sound_precache[i] := S_RegisterSound(cl.configstrings[CS_SOUNDS + i]);
Sys_SendKeyEvents(); // pump message loop
end;
S_EndRegistration();
end;
{*
=====================
CL_ParseDownload
A download message has been received from the server
=====================
*}
procedure CL_ParseDownload();
var
size, percent: Integer;
name: array[0..MAX_OSPATH - 1] of char;
r: boolean;
oldn: array[0..MAX_OSPATH - 1] of char;
newn: array[0..MAX_OSPATH - 1] of char;
begin
// read the data
size := MSG_ReadShort(net_message);
percent := MSG_ReadByte(net_message);
if (size = -1) then
begin
Com_Printf('Server does not have this file.'#10);
if (cls.download > 0) then
begin
// if here, we tried to resume a file but the server said no
FileClose(cls.download);
cls.download := 0;
end;
CL_RequestNextDownload();
exit;
end;
// open the file if not opened yet
if (cls.download <= 0) then
begin
CL_DownloadFileName(name, sizeof(name), cls.downloadtempname);
FS_CreatePath(name);
cls.download := FileOpen(name, fmOpenReadWrite);
if (cls.download = -1) then
begin
net_message.readcount := net_message.readcount + size;
Com_Printf('Failed to open %s'#10, [cls.downloadtempname]);
CL_RequestNextDownload();
cls.download := 0;
exit;
end;
end;
FileWrite(cls.download, Pointer(Cardinal(net_message.data) + net_message.readcount)^, size);
net_message.readcount := net_message.readcount + size;
if (percent <> 100) then
begin
// request next block
// change display routines by zoid
{
Com_Printf (".");
if (10*(percent/10) != cls.downloadpercent)
begin
cls.downloadpercent = 10*(percent/10);
Com_Printf ("%i%%", cls.downloadpercent);
end;
}
cls.downloadpercent := percent;
MSG_WriteByte(cls.netchan.message, Integer(clc_stringcmd));
SZ_Print(cls.netchan.message, 'nextdl');
end
else
begin
// Com_Printf ("100%%\n");
FileClose(cls.download);
// rename the temp file to it's final name
CL_DownloadFileName(oldn, sizeof(oldn), cls.downloadtempname);
CL_DownloadFileName(newn, sizeof(newn), cls.downloadname);
r := renamefile(oldn, newn);
if (not r) then
Com_Printf('failed to rename.'#10);
cls.download := 0;
cls.downloadpercent := 0;
// get another file if needed
CL_RequestNextDownload();
end;
end;
{*
=====================================================================
SERVER CONNECTING MESSAGES
=====================================================================
*}
{*
==================
CL_ParseServerData
==================
*}
procedure CL_ParseServerData();
var
str: PChar;
i: Integer;
begin
Com_DPrintf('Serverdata packet received.'#10);
//
// wipe the client_state_t struct
//
CL_ClearState();
cls.state := ca_connected;
// parse protocol version number
i := MSG_ReadLong(net_message);
cls.serverProtocol := i;
// BIG HACK to let demos from release work with the 3.0x patch!!!
if (Com_ServerState() <> 0) and (PROTOCOL_VERSION = 34) then
begin
end
else if (i <> PROTOCOL_VERSION) then
Com_Error(ERR_DROP, 'Server returned version %i, not %i', [i, PROTOCOL_VERSION]);
cl.servercount := MSG_ReadLong(net_message);
cl.attractloop := MSG_ReadByte(net_message) <> 0;
// game directory
str := MSG_ReadString(net_message);
strncpy(cl.gamedir, str, sizeof(cl.gamedir) - 1);
// set gamedir
if ((str^ <> #0) and ((fs_gamedirvar^.string_ = nil) or (fs_gamedirvar^.string_^ = #0) or (strcmp(fs_gamedirvar^.string_, str) <> 0)) or
((str^ = #0) and ((fs_gamedirvar^.string_ <> nil) or (fs_gamedirvar^.string_^ <> #0)))) then
Cvar_Set('game', str);
// parse player entity number
cl.playernum := MSG_ReadShort(net_message);
// get the full level name
str := MSG_ReadString(net_message);
if (cl.playernum = -1) then
begin
// playing a cinematic or showing a pic, not a level
SCR_PlayCinematic(str);
end
else
begin
// seperate the printfs so the server message can have a color
Com_Printf(#10#10#29#30#30#30#30#30#30#30#30#30#30#30#30#30#30#30#30#30#30#30#30#30#30#30#30#30#30#30#30#30#30#30#30#30#30#30#31#10#10);
Com_Printf('%s%s'#10, [#2, str]);
// need to prep refresh at next oportunity
cl.refresh_prepped := false;
end;
end;
{*
==================
CL_ParseBaseline
==================
*}
procedure CL_ParseBaseline();
var
es: entity_state_p;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -