Ignore:
Timestamp:
Nov 30, 2023, 10:16:14 PM (6 months ago)
Author:
chronos
Message:
  • Modified: Updated high dpi branch from trunk.
  • Modified: Use generics.collections instead of fgl.
  • Modified: Compile with Delphi syntax.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/highdpi/CmdList.pas

    r361 r465  
    55
    66uses
    7   Classes;
     7  Classes, SysUtils, Math;
    88
    99const
    1010  MaxDataSize = 1024;
     11  CommandDataElementSize = 4;
     12  CommandDataElementCountMask = $F;
     13  CommandDataMaxSize = CommandDataElementSize * CommandDataElementCountMask;
    1114
    1215type
     
    2427    constructor Create;
    2528    destructor Destroy; override;
    26     procedure Get(var Command, Player, Subject: integer; var Data: pointer);
    27     procedure GetDataChanges(Data: pointer; DataSize: integer);
    28     procedure Put(Command, Player, Subject: integer; Data: pointer);
    29     procedure PutDataChanges(Command, Player: integer;
    30       OldData, NewData: pointer; DataSize: integer);
    31     procedure LoadFromFile(const f: TFileStream);
    32     procedure SaveToFile(const f: TFileStream);
    33     procedure AppendToFile(const f: TFileStream; const OldState: TCmdListState);
     29    procedure Get(var Command, Player, Subject: Integer; var Data: Pointer);
     30    procedure GetDataChanges(Data: Pointer; DataSize: Integer);
     31    procedure Put(Command, Player, Subject: Integer; Data: Pointer);
     32    procedure PutDataChanges(Command, Player: Integer;
     33      OldData, NewData: Pointer; DataSize: Integer);
     34    procedure LoadFromFile(const F: TFileStream);
     35    procedure SaveToFile(const F: TFileStream);
     36    procedure AppendToFile(const F: TFileStream; const OldState: TCmdListState);
    3437    procedure Cut;
    35     function Progress: integer;
     38    function Progress: Integer;
    3639  private
    37     LogAlloc: integer; { allocated size of LogData in bytes }
     40    LogAlloc: Integer; { allocated size of LogData in bytes }
    3841    LogData: ^TLogData;
    3942    FState: TCmdListState;
    40     procedure PutData(Data: pointer; Length: integer);
     43    procedure PutData(Data: Pointer; Length: Integer);
    4144    procedure CompleteMoveCode;
    4245  public
     
    4447  end;
    4548
     49  function CommandWithData(Command: Integer; DataSize: Byte): Integer;
     50
     51resourcestring
     52  SCommandDataSizeError = 'Command data size %d out of range (0-%d).';
     53
     54
    4655implementation
    4756
     
    5362
    5463type
    55   TData = array [0 .. MaxDataSize - 1] of Cardinal;
     64  TData = array [0..MaxDataSize - 1] of Cardinal;
    5665  PData = ^TData;
     66
     67function CommandWithData(Command: Integer; DataSize: Byte): Integer;
     68var
     69  DataElementCount: Byte;
     70begin
     71  if DataSize > CommandDataMaxSize then
     72    raise Exception.Create(Format(SCommandDataSizeError, [DataSize, CommandDataMaxSize]));
     73  DataElementCount := Ceil(DataSize / CommandDataElementSize);
     74  Result := Command or (DataElementCount and CommandDataElementCountMask);
     75end;
    5776
    5877constructor TCmdList.Create;
     
    7392end;
    7493
    75 procedure TCmdList.Get(var Command, Player, Subject: integer; var Data: pointer);
     94procedure TCmdList.Get(var Command, Player, Subject: Integer; var Data: Pointer);
    7695var
    7796  DirCode: Cardinal;
     
    108127  else
    109128  begin
    110     code := Cardinal((@LogData[FState.LoadPos])^);
    111     if code and 3 = 0 then
     129    Code := Cardinal((@LogData[FState.LoadPos])^);
     130    if Code and 3 = 0 then
    112131    begin // non-clientex command
    113       Command := code shr 2 and $3FFF + sExecute;
    114       Player := code shr 16 and $F;
    115       Subject := code shr 20 and $FFF;
    116       inc(FState.LoadPos, 4);
    117     end
    118     else if code and 7 = 2 then
     132      Command := Code shr 2 and $3FFF + sExecute;
     133      Player := Code shr 16 and $F;
     134      Subject := Code shr 20 and $FFF;
     135      Inc(FState.LoadPos, 4);
     136    end
     137    else if Code and 7 = 2 then
    119138    begin // clientex command
    120       Command := code shr 3 and $FFFF;
    121       Player := code shr 19 and $F;
     139      Command := Code shr 3 and $FFFF;
     140      Player := Code shr 19 and $F;
    122141      Subject := 0;
    123       inc(FState.LoadPos, 3);
     142      Inc(FState.LoadPos, 3);
    124143    end
    125144    else
    126145    begin // move command shortcut
    127       if (code and 1 = 1) and (code and (7 shl 4) <> 6 shl 4) then
     146      if (Code and 1 = 1) and (Code and (7 shl 4) <> 6 shl 4) then
    128147      begin
    129         FState.LoadMoveCode := code and $FF;
    130         inc(FState.LoadPos);
     148        FState.LoadMoveCode := Code and $FF;
     149        Inc(FState.LoadPos);
    131150      end
    132151      else
    133152      begin
    134         FState.LoadMoveCode := code and $FFFFFF;
    135         inc(FState.LoadPos, 3);
     153        FState.LoadMoveCode := Code and $FFFFFF;
     154        Inc(FState.LoadPos, 3);
    136155      end;
    137156      Get(Command, Player, Subject, Data);
     
    139158    end;
    140159
    141     if Command and $F = 0 then
     160    if Command and CommandDataElementCountMask = 0 then
    142161      Data := nil
    143162    else
    144163    begin
    145164      Data := @LogData[FState.LoadPos];
    146       inc(FState.LoadPos, Command and $F * 4);
    147     end;
    148   end;
    149 end;
    150 
    151 procedure TCmdList.GetDataChanges(Data: pointer; DataSize: integer);
     165      Inc(FState.LoadPos, Command and CommandDataElementCountMask * CommandDataElementSize);
     166    end;
     167  end;
     168end;
     169
     170procedure TCmdList.GetDataChanges(Data: Pointer; DataSize: Integer);
    152171var
    153   b0, b1: integer;
     172  b0, b1: Integer;
    154173  Map0, Map1: Cardinal;
    155174begin
    156175  Map0 := Cardinal((@LogData[FState.LoadPos])^);
    157   inc(FState.LoadPos, 4);
     176  Inc(FState.LoadPos, 4);
    158177  b0 := 0;
    159178  while Map0 > 0 do begin
    160179    if Map0 and 1 <> 0 then begin
    161180      Map1 := Cardinal((@LogData[FState.LoadPos])^);
    162       inc(FState.LoadPos, 4);
     181      Inc(FState.LoadPos, 4);
    163182      for b1 := 0 to 31 do
    164183        if 1 shl b1 and Map1 <> 0 then begin
    165184          if b0 * 32 + b1 < DataSize then
    166185            PData(Data)[b0 * 32 + b1] := Cardinal((@LogData[FState.LoadPos])^);
    167           inc(FState.LoadPos, 4);
     186          Inc(FState.LoadPos, 4);
    168187        end;
    169188    end;
    170     inc(b0);
     189    Inc(b0);
    171190    Map0 := Map0 shr 1;
    172191  end;
    173192end;
    174193
    175 procedure TCmdList.Put(Command, Player, Subject: integer; Data: pointer);
     194procedure TCmdList.Put(Command, Player, Subject: Integer; Data: Pointer);
    176195var
    177   DirCode, code: Cardinal;
     196  DirCode, Code: Cardinal;
    178197begin
    179198  if Command and $FC00 = sMoveUnit then
     
    190209    end;
    191210    if Subject = FState.LastMovingUnit then
    192       code := 1 + DirCode shl 1
    193     else
    194       code := 6 + DirCode shl 3 + Cardinal(Subject) shl 6;
     211      Code := 1 + DirCode shl 1
     212    else
     213      Code := 6 + DirCode shl 3 + Cardinal(Subject) shl 6;
    195214    if FState.MoveCode = 0 then
    196       FState.MoveCode := code
     215      FState.MoveCode := Code
    197216    else if FState.MoveCode and 1 = 1 then
    198217    begin // FM + this
    199       FState.MoveCode := FState.MoveCode + code shl 4;
    200       if code and 1 = 1 then
     218      FState.MoveCode := FState.MoveCode + Code shl 4;
     219      if Code and 1 = 1 then
    201220        PutData(@FState.MoveCode, 1) // FM + FM
    202221      else
     
    204223      FState.MoveCode := 0;
    205224    end
    206     else if code and 1 = 1 then
     225    else if Code and 1 = 1 then
    207226    begin // M + FM
    208       FState.MoveCode := FState.MoveCode + code shl 18;
     227      FState.MoveCode := FState.MoveCode + Code shl 18;
    209228      PutData(@FState.MoveCode, 3);
    210229      FState.MoveCode := 0;
     
    213232    begin
    214233      PutData(@FState.MoveCode, 3);
    215       FState.MoveCode := code;
     234      FState.MoveCode := Code;
    216235    end;
    217236    FState.LastMovingUnit := Subject;
     
    222241    if Command >= cClientEx then
    223242    begin
    224       code := 2 + Command shl 3 + Player shl 19;
    225       PutData(@code, 3);
    226     end
    227     else
    228     begin
    229       code := Cardinal(Command - sExecute) shl 2 + Cardinal(Player) shl 16 +
     243      Code := 2 + Command shl 3 + Player shl 19;
     244      PutData(@Code, 3);
     245    end
     246    else
     247    begin
     248      Code := Cardinal(Command - sExecute) shl 2 + Cardinal(Player) shl 16 +
    230249        Cardinal(Subject) shl 20;
    231       PutData(@code, 4);
    232     end;
    233   end;
    234   if Command and $F <> 0 then
    235     PutData(Data, Command and $F * 4);
    236 end;
    237 
    238 procedure TCmdList.PutDataChanges(Command, Player: integer;
    239   OldData, NewData: pointer; DataSize: integer);
     250      PutData(@Code, 4);
     251    end;
     252  end;
     253  if Command and CommandDataElementCountMask <> 0 then
     254    PutData(Data, Command and CommandDataElementCountMask * CommandDataElementSize);
     255end;
     256
     257procedure TCmdList.PutDataChanges(Command, Player: Integer;
     258  OldData, NewData: Pointer; DataSize: Integer);
    240259var
    241   MapPos, LogPos, b0, b1, RowEnd: integer;
    242   Map0, Map1, code: Cardinal;
     260  MapPos, LogPos, b0, b1, RowEnd: Integer;
     261  Map0, Map1, Code: Cardinal;
    243262begin
    244263  if DataSize <= 0 then
    245     exit;
     264    Exit;
    246265  if DataSize > MaxDataSize then
    247266    DataSize := MaxDataSize;
     
    254273    if LogPos + 4 * 32 > LogAlloc then
    255274    begin
    256       inc(LogAlloc, LogGrow);
     275      Inc(LogAlloc, LogGrow);
    257276      ReallocMem(LogData, LogAlloc);
    258277    end;
     
    268287      begin
    269288        Cardinal((@LogData[LogPos])^) := PData(NewData)[b1];
    270         inc(LogPos, 4);
    271         inc(Map1, $80000000);
     289        Inc(LogPos, 4);
     290        Inc(Map1, $80000000);
    272291      end;
    273292    end;
     
    277296      Cardinal((@LogData[MapPos])^) := Map1;
    278297      MapPos := LogPos;
    279       inc(LogPos, 4);
    280       inc(Map0, $80000000);
     298      Inc(LogPos, 4);
     299      Inc(Map0, $80000000);
    281300    end;
    282301  end;
    283302  if Map0 = 0 then
    284     exit; // no changes
     303    Exit; // no changes
    285304
    286305  Map0 := Map0 shr (31 - (DataSize - 1) div 32);
    287306  Cardinal((@LogData[FState.nLog + 4])^) := Map0;
    288   code := Cardinal(Command - sExecute) shl 2 + Cardinal(Player) shl 16;
    289   Cardinal((@LogData[FState.nLog])^) := code;
     307  Code := Cardinal(Command - sExecute) shl 2 + Cardinal(Player) shl 16;
     308  Cardinal((@LogData[FState.nLog])^) := Code;
    290309  FState.nLog := MapPos;
    291310end;
    292311
    293 procedure TCmdList.PutData(Data: pointer; Length: integer);
     312procedure TCmdList.PutData(Data: Pointer; Length: Integer);
    294313begin
    295314  if FState.nLog + Length > LogAlloc then
    296315  begin
    297     inc(LogAlloc, LogGrow);
     316    Inc(LogAlloc, LogGrow);
    298317    ReallocMem(LogData, LogAlloc);
    299318  end;
    300   move(Data^, LogData[FState.nLog], Length);
    301   inc(FState.nLog, Length);
     319  Move(Data^, LogData[FState.nLog], Length);
     320  Inc(FState.nLog, Length);
    302321end;
    303322
     
    314333end;
    315334
    316 procedure TCmdList.LoadFromFile(const f: TFileStream);
    317 begin
    318   f.read(FState.nLog, 4);
     335procedure TCmdList.LoadFromFile(const F: TFileStream);
     336begin
     337  F.Read(FState.nLog, 4);
    319338  LogData := nil;
    320339  LogAlloc := ((FState.nLog + 2) div LogGrow + 1) * LogGrow;
    321340  ReallocMem(LogData, LogAlloc);
    322   f.read(LogData^, FState.nLog);
     341  F.Read(LogData^, FState.nLog);
    323342  FState.LoadPos := 0;
    324343end;
    325344
    326 procedure TCmdList.SaveToFile(const f: TFileStream);
     345procedure TCmdList.SaveToFile(const F: TFileStream);
    327346begin
    328347  CompleteMoveCode;
    329   f.write(FState.nLog, 4);
    330   f.write(LogData^, FState.nLog);
    331 end;
    332 
    333 procedure TCmdList.AppendToFile(const f: TFileStream;
     348  F.Write(FState.nLog, 4);
     349  F.Write(LogData^, FState.nLog);
     350end;
     351
     352procedure TCmdList.AppendToFile(const F: TFileStream;
    334353  const OldState: TCmdListState);
    335354begin
    336355  CompleteMoveCode;
    337   f.write(FState.nLog, 4);
    338   f.Position := f.Position + OldState.nLog;
    339   f.write(LogData[OldState.nLog], FState.nLog - OldState.nLog);
     356  F.Write(FState.nLog, 4);
     357  F.Position := F.Position + OldState.nLog;
     358  F.Write(LogData[OldState.nLog], FState.nLog - OldState.nLog);
    340359end;
    341360
     
    345364end;
    346365
    347 function TCmdList.Progress: integer;
     366function TCmdList.Progress: Integer;
    348367begin
    349368  if (FState.LoadPos = FState.nLog) and (FState.LoadMoveCode = 0) then
    350     result := 1000 // loading complete
     369    Result := 1000 // loading complete
    351370  else if FState.nLog > 1 shl 20 then
    352     result := (FState.LoadPos shr 8) * 999 div (FState.nLog shr 8)
     371    Result := (FState.LoadPos shr 8) * 999 div (FState.nLog shr 8)
    353372  else
    354     result := FState.LoadPos * 999 div FState.nLog;
     373    Result := FState.LoadPos * 999 div FState.nLog;
    355374end;
    356375
     
    360379  Byte3    Byte2    Byte1    Byte0
    361380  ssssssss sssspppp cccccccc cccccc00
    362   (c = Command-sExecute, p = Player, s = Subject)
     381  (C = Command-sExecute, P = Player, S = Subject)
    363382
    364383  ClientEx-Command:
    365384  Byte2    Byte1    Byte0
    366385  0ppppccc cccccccc ccccc010
    367   (c = Command, p = Player)
     386  (C = Command, P = Player)
    368387
    369388  Single Move:
    370389  Byte2    Byte1    Byte0
    371390  000000ss ssssssss ssaaa110
    372   (a = Direction, s = Subject)
     391  (A = Direction, S = Subject)
    373392
    374393  Move + Follow Move:
    375394  Byte2    Byte1    Byte0
    376395  00bbb1ss ssssssss ssaaa110
    377   (a = Direction 1, s = Subject 1, b = Direction 2)
     396  (A = Direction 1, S = Subject 1, B = Direction 2)
    378397
    379398  Follow Move + Move:
    380399  Byte2    Byte1    Byte0
    381400  00ssssss ssssssbb b110aaa1
    382   (a = Direction 1, b = Direction 2, s = Subject 2)
     401  (A = Direction 1, B = Direction 2, S = Subject 2)
    383402
    384403  Single Follow Move:
    385404  Byte0
    386405  0000aaa1
    387   (a = Direction)
     406  (A = Direction)
    388407
    389408  Double Follow Move:
    390409  Byte0
    391410  bbb1aaa1
    392   (a = Direction 1, b = Direction 2)
     411  (A = Direction 1, B = Direction 2)
    393412}
    394413
Note: See TracChangeset for help on using the changeset viewer.