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

📄 sv_ents.pas

📁 delphi编的不错的贪吃蛇
💻 PAS
📖 第 1 页 / 共 2 页
字号:
  // write the rest of the player_state_t
  //
  if (pflags and PS_VIEWOFFSET) <> 0 then
  begin
    MSG_WriteChar(msg^, Round(ps^.viewoffset[0] * 4));
    MSG_WriteChar(msg^, Round(ps^.viewoffset[1] * 4));
    MSG_WriteChar(msg^, Round(ps^.viewoffset[2] * 4));
  end;

  if (pflags and PS_VIEWANGLES) <> 0 then
  begin
    MSG_WriteAngle16(msg^, ps^.viewangles[0]);
    MSG_WriteAngle16(msg^, ps^.viewangles[1]);
    MSG_WriteAngle16(msg^, ps^.viewangles[2]);
  end;

  if (pflags and PS_KICKANGLES) <> 0 then
  begin
    MSG_WriteChar(msg^, Trunc(ps^.kick_angles[0] * 4));
    MSG_WriteChar(msg^, Trunc(ps^.kick_angles[1] * 4));
    MSG_WriteChar(msg^, Trunc(ps^.kick_angles[2] * 4));
  end;

  if (pflags and PS_WEAPONINDEX) <> 0 then
  begin
    MSG_WriteByte(msg^, ps^.gunindex);
  end;

  if (pflags and PS_WEAPONFRAME) <> 0 then
  begin
    MSG_WriteByte(msg^, ps^.gunframe);
    MSG_WriteChar(msg^, Trunc(ps^.gunoffset[0] * 4));
    MSG_WriteChar(msg^, Trunc(ps^.gunoffset[1] * 4));
    MSG_WriteChar(msg^, Trunc(ps^.gunoffset[2] * 4));
    MSG_WriteChar(msg^, Trunc(ps^.gunangles[0] * 4));
    MSG_WriteChar(msg^, Trunc(ps^.gunangles[1] * 4));
    MSG_WriteChar(msg^, Trunc(ps^.gunangles[2] * 4));
  end;

  if (pflags and PS_BLEND) <> 0 then
  begin
    MSG_WriteByte(msg^, Trunc(ps^.blend[0] * 255));
    MSG_WriteByte(msg^, Trunc(ps^.blend[1] * 255));
    MSG_WriteByte(msg^, Trunc(ps^.blend[2] * 255));
    MSG_WriteByte(msg^, Trunc(ps^.blend[3] * 255));
  end;
  if (pflags and PS_FOV) <> 0 then
    MSG_WriteByte(msg^, Trunc(ps^.fov));

  if (pflags and PS_RDFLAGS) <> 0 then
    MSG_WriteByte(msg^, ps^.rdflags);

  // send stats
  statbits := 0;
  for i := 0 to (MAX_STATS - 1) do
    if (ps^.stats[i] <> ops^.stats[i]) then
      statbits := statbits or (1 shl i);

  MSG_WriteLong(msg^, statbits);

  for i := 0 to (MAX_STATS - 1) do
    if (statbits and (1 shl i) <> 0) then
      MSG_WriteShort(msg^, ps^.stats[i]);
end;

(*
==================
SV_WriteFrameToClient
==================
*)

procedure SV_WriteFrameToClient(client: client_p; msg: sizebuf_p);
var
  frame, oldframe: client_frame_p;
  lastframe: Integer;
begin
  { Following line commented in Original Source }
  //Com_Printf ("%i -> %i\n", client->lastframe, sv.framenum);
    // this is the frame we are creating
  frame := @client^.frames[sv.framenum and UPDATE_MASK];

  if (client^.lastframe <= 0) then
  begin
    // client is asking for a retransmit
    oldframe := nil;
    lastframe := -1;
  end
  else if (sv.framenum - client^.lastframe >= (UPDATE_BACKUP - 3)) then
  begin
    // client hasn't gotten a good message through in a long time
    { Following line commented in Original Source }
    // Com_Printf ("%s: Delta request from out-of-date packet.\n", client->name);
    oldframe := nil;
    lastframe := -1;
  end
  else
  begin
    // we have a valid message to delta from
    oldframe := @client^.frames[client^.lastframe and UPDATE_MASK];
    lastframe := client^.lastframe;
  end;

  MSG_WriteByte(msg^, Integer(svc_frame));
  MSG_WriteLong(msg^, sv.framenum);
  MSG_WriteLong(msg^, lastframe);       // what we are delta'ing from
  MSG_WriteByte(msg^, client^.surpressCount); // rate dropped packets
  client^.surpressCount := 0;

  // send over the areabits
  MSG_WriteByte(msg^, frame^.areabytes);
  SZ_Write(msg^, @frame^.areabits, frame^.areabytes);

  // delta encode the playerstate
  SV_WritePlayerstateToClient(oldframe, frame, msg);

  // delta encode the entities
  SV_EmitPacketEntities(oldframe, frame, msg^);
end;

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

Build a client frame structure

============================================================================= *)

var
  fatpvs: array[0..(65536 div 8) - 1] of byte; // 32767 is MAX_MAP_LEAFS

  (*
  ============
  SV_FatPVS

  The client will interpolate the view position,
  so we can't use a single PVS point
  ===========
  *)

procedure SV_FatPVS(const org: vec3_t);
var
  leafs: array[0..64 - 1] of Integer;
  i, j, count: Integer;
  longs: Integer;
  src: PIntegerArray;
  mins, maxs: vec3_t;
begin
  for i := 0 to 2 do
  begin
    mins[i] := org[i] - 8;
    maxs[i] := org[i] + 8;
  end;

  count := CM_BoxLeafnums(mins, maxs, @leafs, 64, nil);
  if (count < 1) then
    Com_Error(ERR_FATAL, 'SV_FatPVS: count < 1', []);

  longs := (CM_NumClusters + 31) shr 5;

  // convert leafs to clusters
  for i := 0 to (count - 1) do
    leafs[i] := CM_LeafCluster(leafs[i]);

  move(CM_ClusterPVS(leafs[0])^, fatpvs, longs shl 2);
  // or in all the other leaf bits
  for i := 1 to (count - 1) do
  begin
    for j := 0 to (i - 1) do
      if (leafs[i] = leafs[j]) then
        Break;

    if (j <> i) then
      Continue;                         // already have the cluster we want

    src := PIntegerArray(CM_ClusterPVS(leafs[i]));
    for j := 0 to (longs - 1) do
      PIntegerArray(@fatpvs)^[j] := PIntegerArray(@fatpvs)^[j] or src[j];
  end;
end;

(*
=============
SV_BuildClientFrame

Decides which entities are going to be visible to the client, and
copies off the playerstat and areabits.
=============
*)

procedure SV_BuildClientFrame(client: client_p);
var
  e, i: Integer;
  org: vec3_t;
  ent: edict_p;
  clent: edict_p;
  frame: client_frame_p;
  state: entity_state_p;
  l: Integer;
  clientarea, clientcluster: Integer;
  leafnum: Integer;
  c_fullsend: Integer;
  clientphs: PByteArray;
  bitvector: PByteArray;
  delta: vec3_t;
  len: single;
begin
  clent := client.edict;
  if (clent.client = nil) then
    Exit;                               // not in game yet

  {
    numprojs := 0; // no projectiles yet
  }

    // this is the frame we are creating
  frame := @client.frames[sv.framenum and UPDATE_MASK];

  frame.senttime := svs.realtime;       // save it for ping calc later

  // find the client's PVS
  for i := 0 to 2 do
    org[i] := (clent.client^.ps.pmove.origin[i] * 0.125) + clent.client^.ps.viewoffset[i];

  leafnum := CM_PointLeafnum(org);
  clientarea := CM_LeafArea(leafnum);
  clientcluster := CM_LeafCluster(leafnum);

  // calculate the visible areas
  frame.areabytes := CM_WriteAreaBits(@frame.areabits, clientarea);

  // grab the current player_state_t
  frame.ps := clent.client^.ps;

  SV_FatPVS(org);
  clientphs := PByteArray(CM_ClusterPHS(clientcluster));

  // build up the list of visible entities
  frame.num_entities := 0;
  frame.first_entity := svs.next_client_entities;

  c_fullsend := 0;

  for e := 1 to (ge.num_edicts - 1) do
  begin
    ent := EDICT_NUM(e);

    // ignore ents without visible models
    if (ent.svflags and SVF_NOCLIENT) <> 0 then
      Continue;

    // ignore ents without visible models unless they have an effect
    if ((ent.s.modelindex = 0) and (ent.s.effects = 0) and (ent.s.sound = 0) and
      (Integer(ent.s.event) = 0)) then
      Continue;

    // ignore if not touching a PV leaf
    if (ent <> clent) then
    begin
      // check area
      if (not CM_AreasConnected(clientarea, ent^.areanum)) then
      begin
        // doors can legally straddle two areas, so
         // we may need to check another one
        if (ent^.areanum2 = 0) or (not CM_AreasConnected(clientarea, ent^.areanum2)) then
          Continue;                     // blocked by a door
      end;

      // beams just check one point for PHS
      if (ent^.s.renderfx and RF_BEAM) <> 0 then
      begin
        l := ent^.clusternums[0];
        if ((clientphs[l shr 3] and (1 shl (l and 7))) = 0) then
          Continue;
      end
      else
      begin
        // FIXME: if an ent has a model and a sound, but isn't
        // in the PVS, only the PHS, clear the model
        if (ent^.s.sound <> 0) then
        begin
          bitvector := @fatpvs;         //clientphs;
        end
        else
          bitvector := @fatpvs;

        if (ent^.num_clusters = -1) then
        begin
          // too many leafs for individual check, go by headnode
          if (not CM_HeadnodeVisible(ent^.headnode, bitvector)) then
            Continue;
          Inc(c_fullsend);
        end
        else
        begin
          // check individual leafs
          i := 0;
          while (i < ent^.num_clusters) do
          begin
            l := ent^.clusternums[i];
            if (bitvector[l shr 3] and (1 shl (l and 7))) <> 0 then
              Break;
            inc(i);
          end;

          if (i = ent^.num_clusters) then
            Continue;                   // not visible
        end;

        if (ent^.s.modelindex = 0) then
        begin
          // don't send sounds if they will be attenuated away
          VectorSubtract(org, ent^.s.origin, delta);
          len := VectorLength(delta);
          if (len > 400) then
            Continue;
        end;
      end;
    end;

    {
        if (SV_AddProjectileUpdate(ent) <> 0) then
          Continue; // added as a special projectile
    }

        // add it to the circular client_entities array
    state := @svs.client_entities^[svs.next_client_entities mod svs.num_client_entities];
    if (ent^.s.number <> e) then
    begin
      Com_DPrintf('FIXING ENT->S.NUMBER!!!'#10, []);
      ent^.s.number := e;
    end;

    state^ := ent^.s;

    // don't mark players missiles as solid
    if (ent^.owner = client^.edict) then
      state^.solid := 0;

    Inc(svs.next_client_entities);
    Inc(frame^.num_entities);
  end;
end;

(*
==================
SV_RecordDemoMessage

Save everything in the world out without deltas.
Used for recording footage for merged or assembled demos
==================
*)

procedure SV_RecordDemoMessage;
var
  e: Integer;
  ent: edict_p;
  nostate: entity_state_t;
  buf: sizebuf_t;
  buf_data: array[0..32768 - 1] of byte;
  len: Integer;
begin
  if (svs.demofile <= 0) then
    Exit;

  FillChar(nostate, SizeOf(nostate), 0);
  SZ_Init(buf, @buf_data, SizeOf(buf_data));

  // write a frame message that doesn't contain a player_state_t
  MSG_WriteByte(buf, Integer(svc_frame));
  MSG_WriteLong(buf, sv.framenum);

  MSG_WriteByte(buf, Integer(svc_packetentities));

  e := 1;
  ent := EDICT_NUM(e);
  while (e < ge^.num_edicts) do
  begin
    // ignore ents without visible models unless they have an effect
    if (ent^.inuse) and (ent^.s.number <> 0) and ((ent^.s.modelindex <> 0) or (ent^.s.effects <> 0) or (ent^.s.sound <> 0) or (Integer(ent^.s.event) <> 0)) and
      ((ent^.svflags and SVF_NOCLIENT) = 0) then
      MSG_WriteDeltaEntity(nostate, ent^.s, buf, false, true);

    Inc(e);
    ent := EDICT_NUM(e);
  end;

  MSG_WriteShort(buf, 0);               // end of packetentities

  // now add the accumulated multicast information
  SZ_Write(buf, svs.demo_multicast.data, svs.demo_multicast.cursize);
  SZ_Clear(svs.demo_multicast);

  // now write the entire message to the file, prefixed by the length
  len := LittleLong(buf.cursize);
  FileWrite(svs.demofile, len, 4);
  FileWrite(svs.demofile, buf.data, buf.cursize);
end;

end.

⌨️ 快捷键说明

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