📄 cl_ents.pas
字号:
{100%}
{----------------------------------------------------------------------------}
{ }
{ File(s): cl_ents.c }
{ Content: Quake2\Client - builds an intended movement command to send to the server }
{ }
{ Initial conversion by : Dart - hanhpham@web.de }
{ Initial conversion on : 04-April-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: }
{ 03-Jun-2002 Juha Hartikainen (juha@linearteam.org) }
{ - MANY language fixes }
{ }
{ 08-Jun-2002 Juha Hartikainen (juha@linearteam.org) }
{ - Finished conversion. }
{ }
{ * ToDo: }
{ - All places with TODO define }
{----------------------------------------------------------------------------}
{.$DEFINE TODO}
unit cl_ents;
interface
uses
client,
q_shared_add,
q_shared;
procedure CL_AddEntities;
procedure CL_GetEntitySoundOrigin(ent: integer; var org: vec3_t);
function CL_ParseEntityBits(bits: PCardinal): integer;
procedure CL_ParseDelta(pfrom: entity_state_p; pto: entity_state_p; number: integer; bits: integer);
procedure CL_ParseFrame;
var
//PGM
vidref_val: integer;
//PGM
implementation
uses
Common,
CPas,
net_chan,
cl_scrn,
cl_pred,
cl_main,
cl_view,
Files,
ref,
cl_parse,
cl_newfx,
cl_tent,
{$IFDEF WIN32}
vid_dll,
{$ELSE}
vid_so,
{$ENDIF}
cl_fx;
{*
=========================================================================
FRAME PARSING
=========================================================================
*}
{*
=================
CL_ParseEntityBits
Returns the entity number and the header bits
=================
*}
var
bitcounts: array[0..32 - 1] of integer; /// just for protocol profiling
function CL_ParseEntityBits(bits: PCardinal): integer;
var
b, total: Cardinal;
i: integer;
number: integer;
begin
total := MSG_ReadByte(net_message);
if (total and U_MOREBITS1 <> 0) then
begin
b := MSG_ReadByte(net_message);
total := total or (b shl 8);
end;
if (total and U_MOREBITS2 <> 0) then
begin
b := MSG_ReadByte(net_message);
total := total or (b shl 16);
end;
if (total and U_MOREBITS3 <> 0) then
begin
b := MSG_ReadByte(net_message);
total := total or (b shl 24);
end;
// count the bits for net profiling
for i := 0 to 32 - 1 do
if (total and (1 shl i)) > 0 then
inc(bitcounts[i]);
if (total and U_NUMBER16 <> 0) then
number := MSG_ReadShort(net_message)
else
number := MSG_ReadByte(net_message);
bits^ := total;
result := number;
end;
{*
==================
CL_ParseDelta
Can go from either a baseline or a previous packet_entity
==================
*}
procedure CL_ParseDelta(pfrom: entity_state_p; pto: entity_state_p; number: integer; bits: integer);
begin // set everything to the state we are delta'ing from
pto^ := pfrom^;
VectorCopy(pfrom.origin, pto.old_origin);
pto.number := number;
if (bits and U_MODEL <> 0) then
pto.modelindex := MSG_ReadByte(net_message);
if (bits and U_MODEL2 <> 0) then
pto.modelindex2 := MSG_ReadByte(net_message);
if (bits and U_MODEL3 <> 0) then
pto.modelindex3 := MSG_ReadByte(net_message);
if (bits and U_MODEL4 <> 0) then
pto.modelindex4 := MSG_ReadByte(net_message);
if (bits and U_FRAME8 <> 0) then
pto.frame := MSG_ReadByte(net_message);
if (bits and U_FRAME16 <> 0) then
pto.frame := MSG_ReadShort(net_message);
if (bits and U_SKIN8 <> 0) and
(bits and U_SKIN16 <> 0) then //used for laser colors
pto.skinnum := MSG_ReadLong(net_message)
else if (bits and U_SKIN8 <> 0) then
pto.skinnum := MSG_ReadByte(net_message)
else if (bits and U_SKIN16 <> 0) then
pto.skinnum := MSG_ReadShort(net_message);
if ((bits and (U_EFFECTS8 or U_EFFECTS16)) = (U_EFFECTS8 or U_EFFECTS16)) then
pto.effects := MSG_ReadLong(net_message)
else if (bits and U_EFFECTS8 <> 0) then
pto.effects := MSG_ReadByte(net_message)
else if (bits and U_EFFECTS16 <> 0) then
pto.effects := MSG_ReadShort(net_message);
if ((bits and (U_RENDERFX8 or U_RENDERFX16)) = (U_RENDERFX8 or U_RENDERFX16)) then
pto.renderfx := MSG_ReadLong(net_message)
else if (bits and U_RENDERFX8 <> 0) then
pto.renderfx := MSG_ReadByte(net_message)
else if (bits and U_RENDERFX16 <> 0) then
pto.renderfx := MSG_ReadShort(net_message);
if (bits and U_ORIGIN1 <> 0) then
pto.origin[0] := MSG_ReadCoord(net_message);
if (bits and U_ORIGIN2 <> 0) then
pto.origin[1] := MSG_ReadCoord(net_message);
if (bits and U_ORIGIN3 <> 0) then
pto.origin[2] := MSG_ReadCoord(net_message);
if (bits and U_ANGLE1 <> 0) then
pto.angles[0] := MSG_ReadAngle(net_message);
if (bits and U_ANGLE2 <> 0) then
pto.angles[1] := MSG_ReadAngle(net_message);
if (bits and U_ANGLE3 <> 0) then
pto.angles[2] := MSG_ReadAngle(net_message);
if (bits and U_OLDORIGIN <> 0) then
MSG_ReadPos(net_message, pto.old_origin);
if (bits and U_SOUND <> 0) then
pto.sound := MSG_ReadByte(net_message);
if (bits and U_EVENT <> 0) then
pto.event := entity_event_t(MSG_ReadByte(net_message))
else
pto.event := entity_event_t(0);
if (bits and U_SOLID <> 0) then
pto.solid := MSG_ReadShort(net_message);
end;
{*
==================
CL_DeltaEntity
Parses deltas from the given base and adds the resulting entity
to the current frame
==================
*}
procedure CL_DeltaEntity(frame: frame_p; newnum: integer; old: entity_state_p; bits: integer);
var
ent: centity_p;
state: entity_state_p;
begin
ent := @cl_entities[newnum];
state := @cl_parse_entities[cl.parse_entities and (MAX_PARSE_ENTITIES - 1)];
inc(cl.parse_entities);
inc(frame.num_entities);
CL_ParseDelta(old, state, newnum, bits);
// some data changes will force no lerping
if (state.modelindex <> ent.current.modelindex) or
(state.modelindex2 <> ent.current.modelindex2) or
(state.modelindex3 <> ent.current.modelindex3) or
(state.modelindex4 <> ent.current.modelindex4) or
(abs(state.origin[0] - ent.current.origin[0]) > 512) or
(abs(state.origin[1] - ent.current.origin[1]) > 512) or
(abs(state.origin[2] - ent.current.origin[2]) > 512) or
(state.event = EV_PLAYER_TELEPORT) or
(state.event = EV_OTHER_TELEPORT) then
ent.serverframe := -99;
if (ent.serverframe <> cl.frame.serverframe - 1) then
begin // wasn't in last update, so initialize some things
ent.trailcount := 1024; // for diminishing rocket / grenade trails
// duplicate the current state so lerping doesn't hurt anything
ent.prev := state^;
if (state.event = EV_OTHER_TELEPORT) then
begin
VectorCopy(state.origin, ent.prev.origin);
VectorCopy(state.origin, ent.lerp_origin);
end
else
begin
VectorCopy(state.old_origin, ent.prev.origin);
VectorCopy(state.old_origin, ent.lerp_origin);
end;
end
else
begin // shuffle the last state to previous
ent.prev := ent.current;
end;
ent.serverframe := cl.frame.serverframe;
ent.current := state^;
end;
{*
==================
CL_ParsePacketEntities
An svc_packetentities has just been parsed, deal with the
rest of the data stream.
==================
*}
procedure CL_ParsePacketEntities(oldframe: frame_p; newframe: frame_p);
var
newnum: integer;
bits: Cardinal;
oldstate: entity_state_p;
oldindex, oldnum: integer;
begin
newframe^.parse_entities := cl.parse_entities;
newframe^.num_entities := 0;
// delta from the entities present in oldframe
oldindex := 0;
if (oldframe = nil) then
oldnum := 99999
else
begin
if (oldindex >= oldframe^.num_entities) then
oldnum := 99999
else
begin
oldstate := @cl_parse_entities[(oldframe^.parse_entities + oldindex) and (MAX_PARSE_ENTITIES - 1)];
oldnum := oldstate^.number;
end;
end;
while (true) do
begin
newnum := CL_ParseEntityBits(@bits);
if (newnum >= MAX_EDICTS) then
Com_Error(ERR_DROP, 'CL_ParsePacketEntities: bad number:%d', [newnum]);
if (net_message.readcount > net_message.cursize) then
Com_Error(ERR_DROP, 'CL_ParsePacketEntities: end of message', []);
if (newnum = 0) then
break;
while (oldnum < newnum) do
begin // one or more entities from the old packet are unchanged
if (cl_shownet.value = 3) then
Com_Printf(' unchanged: %d'#10, [oldnum]);
CL_DeltaEntity(newframe, oldnum, oldstate, 0);
inc(oldindex);
if (oldindex >= oldframe^.num_entities) then
oldnum := 99999
else
begin
oldstate := @cl_parse_entities[(oldframe^.parse_entities + oldindex) and (MAX_PARSE_ENTITIES - 1)];
oldnum := oldstate.number;
end;
end;
if (bits and U_REMOVE <> 0) then
begin // the entity present in oldframe is not in the current frame
if (cl_shownet.value = 3) then
Com_Printf(' remove: %d'#10, [newnum]);
if (oldnum <> newnum) then
Com_Printf('U_REMOVE: oldnum != newnum'#10, []);
inc(oldindex);
if (oldindex >= oldframe.num_entities) then
oldnum := 99999
else
begin
oldstate := @cl_parse_entities[(oldframe^.parse_entities + oldindex) and (MAX_PARSE_ENTITIES - 1)];
oldnum := oldstate^.number;
end;
continue;
end;
if (oldnum = newnum) then
begin // delta from previous state
if (cl_shownet.value = 3) then
Com_Printf(' delta: %d'#10, [newnum]);
CL_DeltaEntity(newframe, newnum, oldstate, bits);
inc(oldindex);
if (oldindex >= oldframe^.num_entities) then
oldnum := 99999
else
begin
oldstate := @cl_parse_entities[(oldframe^.parse_entities + oldindex) and (MAX_PARSE_ENTITIES - 1)];
oldnum := oldstate^.number;
end;
continue;
end;
if (oldnum > newnum) then
begin // delta from baseline
if (cl_shownet.value = 3) then
Com_Printf(' baseline: %d'#10, [newnum]);
CL_DeltaEntity(newframe, newnum, @cl_entities[newnum].baseline, bits);
continue;
end;
end;
// any remaining entities in the old frame are copied over
while (oldnum <> 99999) do
begin // one or more entities from the old packet are unchanged
if (cl_shownet.value = 3) then
Com_Printf(' unchanged: %d'#10, [oldnum]);
CL_DeltaEntity(newframe, oldnum, oldstate, 0);
inc(oldindex);
if (oldindex >= oldframe.num_entities) then
oldnum := 99999
else
begin
oldstate := @cl_parse_entities[(oldframe^.parse_entities + oldindex) and (MAX_PARSE_ENTITIES - 1)];
oldnum := oldstate.number;
end;
end;
end;
{*
===================
CL_ParsePlayerstate
===================
*}
procedure CL_ParsePlayerstate(oldframe: frame_p; newframe: frame_p);
var
flags: integer;
state: player_state_p;
i: integer;
statbits: integer;
begin
state := @newframe.playerstate;
// clear to old value before delta parsing
if (oldframe <> nil) then
state^ := oldframe.playerstate
else
FillChar(state^, sizeof(player_state_t), 0);
flags := MSG_ReadShort(net_message);
//
// parse the pmove_state_t
//
if (flags and PS_M_TYPE <> 0) then
state.pmove.pm_type := pmtype_t(MSG_ReadByte(net_message));
if (flags and PS_M_ORIGIN <> 0) then
begin
state.pmove.origin[0] := MSG_ReadShort(net_message);
state.pmove.origin[1] := MSG_ReadShort(net_message);
state.pmove.origin[2] := MSG_ReadShort(net_message);
end;
if (flags and PS_M_VELOCITY <> 0) then
begin
state.pmove.velocity[0] := MSG_ReadShort(net_message);
state.pmove.velocity[1] := MSG_ReadShort(net_message);
state.pmove.velocity[2] := MSG_ReadShort(net_message);
end;
if (flags and PS_M_TIME <> 0) then
state.pmove.pm_time := MSG_ReadByte(net_message);
if (flags and PS_M_FLAGS <> 0) then
state.pmove.pm_flags := MSG_ReadByte(net_message);
if (flags and PS_M_GRAVITY <> 0) then
state.pmove.gravity := MSG_ReadShort(net_message);
if (flags and PS_M_DELTA_ANGLES <> 0) then
begin
state.pmove.delta_angles[0] := MSG_ReadShort(net_message);
state.pmove.delta_angles[1] := MSG_ReadShort(net_message);
state.pmove.delta_angles[2] := MSG_ReadShort(net_message);
end;
if (cl.attractloop) then
state.pmove.pm_type := PM_FREEZE; // demo playback
//
// parse the rest of the player_state_t
//
if (flags and PS_VIEWOFFSET <> 0) then
begin
state.viewoffset[0] := MSG_ReadChar(net_message) * 0.25;
state.viewoffset[1] := MSG_ReadChar(net_message) * 0.25;
state.viewoffset[2] := MSG_ReadChar(net_message) * 0.25;
end;
if (flags and PS_VIEWANGLES <> 0) then
begin
state.viewangles[0] := MSG_ReadAngle16(net_message);
state.viewangles[1] := MSG_ReadAngle16(net_message);
state.viewangles[2] := MSG_ReadAngle16(net_message);
end;
if (flags and PS_KICKANGLES <> 0) then
begin
state.kick_angles[0] := MSG_ReadChar(net_message) * 0.25;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -