Changeset 703 for trunk/MiniMap.pas


Ignore:
Timestamp:
Aug 12, 2025, 3:03:54 PM (36 hours ago)
Author:
chronos
Message:
  • Fixed: Potential mini map loading memory issue if saved map is too big.
  • Fixed: Drawing map preview last line.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/MiniMap.pas

    r595 r703  
    1010type
    1111  TMiniMode = (mmNone, mmPicture, mmMultiPlayer);
    12   TMapArray = array[0 .. lxmax * lymax - 1] of Byte;
     12  TMapArray = array [0 .. lxmax * lymax - 1] of Byte;
    1313
    1414  { TMiniMap }
     
    7070var
    7171  SaveMap: TMapArray;
    72   y: Integer;
    73   Dummy: Integer;
     72  Version: Cardinal;
    7473  FileLandMass: Integer;
    75   LogFile: file;
    76   s: string[255];
    77   MapRow: array [0 .. lxmax - 1] of Cardinal;
    78 begin
    79   AssignFile(LogFile, FileName);
     74  LogFile: TFileStream;
     75  ReadFileId: string;
     76  ExeInfoTime: LongInt;
     77  RNG: Integer;
     78  MaxTurn: Integer;
     79const
     80  FileId = 'cEvoBook';
     81begin
     82  Version := 0;
     83  ExeInfoTime := 0;
     84  FileLandMass := 0;
     85  MaxTurn := 0;
     86  RNG := 0;
     87
     88  LogFile := TFileStream.Create(FileName, fmOpenRead or fmShareExclusive);
    8089  try
    81     Reset(LogFile, 4);
    82     BlockRead(LogFile, s[1], 2); { file id }
    83     BlockRead(LogFile, Dummy, 1); { format id }
    84     if Dummy >= $000E01 then
    85       BlockRead(LogFile, Dummy, 1); { item stored since 0.14.1 }
    86     BlockRead(LogFile, Size.X, 1);
    87     BlockRead(LogFile, Size.Y, 1);
    88     BlockRead(LogFile, FileLandMass, 1);
     90    ReadFileId := default(string);
     91    SetLength(ReadFileId, 8);
     92    LogFile.Read(ReadFileId[1], 8); { file id }
     93    if ReadFileId <> FileId then
     94      raise Exception.Create('Incorrect game file id. Expected ''' + Trim(FileId) +
     95        ''' but ''' + Trim(ReadFileId) + ''' read.');
     96    LogFile.Read(Version, 4); { format id }
     97    if Version >= $000E01 then
     98      LogFile.Read(ExeInfoTime, 4); { item stored since 0.14.1 }
     99    LogFile.Read(Size.X, 4);
     100    LogFile.Read(Size.Y, 4);
     101    LogFile.Read(FileLandMass, 4);
     102
    89103    if FileLandMass = 0 then
    90       for y := 0 to Size.Y - 1 do
    91         BlockRead(LogFile, MapRow, Size.X);
    92     BlockRead(LogFile, Dummy, 1);
    93     BlockRead(LogFile, Dummy, 1);
    94     BlockRead(LogFile, LastTurn, 1);
    95     BlockRead(LogFile, SaveMap, 1);
     104      LogFile.Seek(Size.Y * Size.X * 4, soCurrent);
     105    LogFile.Read(MaxTurn, 4);
     106    LogFile.Read(RNG, 4);
     107    LogFile.Read(LastTurn, 4);
     108    LogFile.Read(SaveMap, 4);
    96109    if SaveMap[0] = $80 then
    97110      Mode := mmMultiPlayer
     
    99112      Mode := mmPicture;
    100113    if Mode = mmPicture then
    101       BlockRead(LogFile, SaveMap[4], (Size.X * Size.Y - 1) div 4);
    102     CloseFile(LogFile);
     114      if Size.X * Size.Y <= Length(SaveMap) then
     115        LogFile.Read(SaveMap[4], Size.X * Size.Y - 4)
     116        else raise Exception.Create('Saved map data too big [' + IntToStr(Size.X) + 'x' + IntToStr(Size.Y) + ']');
     117    LogFile.Free;
    103118  except
    104     CloseFile(LogFile);
     119    LogFile.Free;
    105120    LastTurn := 0;
    106121    Size := DefaultSize;
     
    163178procedure TMiniMap.PaintMap(Map: TMap);
    164179var
    165   i, x, y, xm, cm, Tile: Integer;
     180  I, X, Y, XM, CM, Tile: Integer;
    166181  MiniPixel: TPixelPointer;
    167182  PrevMiniPixel: TPixelPointer;
    168   xx, yy: Integer;
     183  XX, YY: Integer;
    169184begin
    170185  Bitmap.PixelFormat := TPixelFormat.pf24bit;
     
    174189    MiniPixel := TPixelPointer.Create(Bitmap);
    175190    PrevMiniPixel := TPixelPointer.Create(Bitmap);
    176     xx := ScaleToNative(Size.X);
    177     yy := ScaleToNative(Size.Y);
    178     for y := 0 to yy - 1 do begin
    179       for x := 0 to xx - 1 do begin
    180         for i := 0 to 1 do begin
    181           xm := (x * 2 + i + y and 1) mod (xx * 2);
    182           MiniPixel.SetX(xm);
    183           Tile := Map.Tiles[ScaleFromNative(x) + Size.X * ScaleFromNative(y)];
    184           if Tile and fTerrain = fUNKNOWN then cm := $000000
    185             else cm := Colors[Tile and fTerrain, i];
    186           // TODO: Needs to use (yy - 1) to avoid access violation for unknown reason
     191    XX := ScaleToNative(Size.X);
     192    YY := ScaleToNative(Size.Y);
     193    for Y := 0 to YY - 1 do begin
     194      for X := 0 to XX - 1 do begin
     195        for I := 0 to 1 do begin
     196          XM := (X * 2 + I + Y and 1) mod (XX * 2);
     197          MiniPixel.SetX(XM);
     198          Tile := Map.Tiles[ScaleFromNative(X) + Size.X * ScaleFromNative(Y)];
     199          if Tile and fTerrain = fUNKNOWN then CM := $000000
     200            else CM := Colors[Tile and fTerrain, I];
    187201          if (PByte(MiniPixel.Pixel) >= Bitmap.RawImage.Data) and
    188           (PByte(MiniPixel.Pixel) < (Bitmap.RawImage.Data + (yy - 1) * MiniPixel.BytesPerLine)) then begin
    189             MiniPixel.PixelB := (cm shr 16) and $ff;
    190             MiniPixel.PixelG := (cm shr 8) and $ff;
    191             MiniPixel.PixelR := (cm shr 0) and $ff;
     202          (PByte(MiniPixel.Pixel) < (Bitmap.RawImage.Data + YY * MiniPixel.BytesPerLine)) then begin
     203            MiniPixel.PixelB := (CM shr 16) and $ff;
     204            MiniPixel.PixelG := (CM shr 8) and $ff;
     205            MiniPixel.PixelR := (CM shr 0) and $ff;
    192206          end;
    193207        end;
    194208      end;
    195209      MiniPixel.NextLine;
    196       if y > 0 then PrevMiniPixel.NextLine;
     210      if Y > 0 then PrevMiniPixel.NextLine;
    197211    end;
    198212    Bitmap.EndUpdate;
     
    202216procedure TMiniMap.PaintRandom(Brightness, StartLandMass: Integer; WorldSize: TPoint);
    203217var
    204   i, x, y, xm, cm: Integer;
     218  I, X, Y, XM, CM: Integer;
    205219  MiniPixel: TPixelPointer;
    206220  Map: ^TTileList;
    207   xx, yy: Integer;
     221  XX, YY: Integer;
    208222begin
    209223  Map := PreviewMap(StartLandMass);
     
    214228  Bitmap.BeginUpdate;
    215229  MiniPixel := TPixelPointer.Create(Bitmap);
    216   xx := ScaleToNative(Size.X);
    217   yy := ScaleToNative(Size.Y);
    218   for y := 0 to yy - 1 do begin
    219     for x := 0 to xx - 1 do begin
    220       for i := 0 to 1 do begin
    221         xm := (x * 2 + i + y and 1) mod (xx * 2);
    222         MiniPixel.SetX(xm);
    223         cm := Colors[Map[ScaleFromNative(x) * lxmax div Size.X + lxmax *
    224           ((ScaleFromNative(y) * (lymax - 1) + Size.Y div 2) div (Size.Y - 1))] and
     230  XX := ScaleToNative(Size.X);
     231  YY := ScaleToNative(Size.Y);
     232  for Y := 0 to YY - 1 do begin
     233    for X := 0 to XX - 1 do begin
     234      for I := 0 to 1 do begin
     235        XM := (X * 2 + I + Y and 1) mod (XX * 2);
     236        MiniPixel.SetX(XM);
     237        CM := Colors[Map[ScaleFromNative(X) * lxmax div Size.X + lxmax *
     238          ((ScaleFromNative(Y) * (lymax - 1) + Size.Y div 2) div (Size.Y - 1))] and
    225239          fTerrain, I];
    226240        if (PByte(MiniPixel.Pixel) >= Bitmap.RawImage.Data) and
    227         (PByte(MiniPixel.Pixel) < (Bitmap.RawImage.Data + yy * MiniPixel.BytesPerLine)) then begin
    228           MiniPixel.PixelB := ((cm shr 16) and $FF) * Brightness div 3;
    229           MiniPixel.PixelG := ((cm shr 8) and $FF) * Brightness div 3;
    230           MiniPixel.PixelR := ((cm shr 0) and $FF) * Brightness div 3;
     241        (PByte(MiniPixel.Pixel) < (Bitmap.RawImage.Data + YY * MiniPixel.BytesPerLine)) then begin
     242          MiniPixel.PixelB := ((CM shr 16) and $FF) * Brightness div 3;
     243          MiniPixel.PixelG := ((CM shr 8) and $FF) * Brightness div 3;
     244          MiniPixel.PixelR := ((CM shr 0) and $FF) * Brightness div 3;
    231245        end;
    232246      end;
     
    239253procedure TMiniMap.PaintFile(SaveMap: TMapArray);
    240254var
    241   i, x, y, xm, cm, Tile, OwnColor, EnemyColor: integer;
     255  I, X, Y, XM, CM, Tile, OwnColor, EnemyColor: Integer;
    242256  MiniPixel: TPixelPointer;
    243257  PrevMiniPixel: TPixelPointer;
    244   xx, yy: Integer;
     258  XX, YY: Integer;
    245259begin
    246260  OwnColor := HGrSystem.Data.Canvas.Pixels[95, 67];
     
    252266    MiniPixel := TPixelPointer.Create(Bitmap);
    253267    PrevMiniPixel := TPixelPointer.Create(Bitmap);
    254     xx := ScaleToNative(Size.X);
    255     yy := ScaleToNative(Size.Y);
    256     for y := 0 to yy - 1 do begin
    257       for x := 0 to xx - 1 do begin
    258         for i := 0 to 1 do begin
    259           xm := (x * 2 + i + y and 1) mod (xx * 2);
    260           MiniPixel.SetX(xm);
    261           Tile := SaveMap[ScaleFromNative(x) + Size.X * ScaleFromNative(y)];
     268    XX := ScaleToNative(Size.X);
     269    YY := ScaleToNative(Size.Y);
     270    for Y := 0 to YY - 1 do begin
     271      for X := 0 to XX - 1 do begin
     272        for I := 0 to 1 do begin
     273          XM := (X * 2 + I + Y and 1) mod (XX * 2);
     274          MiniPixel.SetX(XM);
     275          Tile := SaveMap[ScaleFromNative(X) + Size.X * ScaleFromNative(Y)];
    262276          if Tile and fTerrain = fUNKNOWN then
    263             cm := $000000
     277            CM := $000000
    264278          else if Tile and smCity <> 0 then begin
    265             if Tile and smOwned <> 0 then cm := OwnColor
    266               else cm := EnemyColor;
    267             if y > 0 then begin
     279            if Tile and smOwned <> 0 then CM := OwnColor
     280              else CM := EnemyColor;
     281            if Y > 0 then begin
    268282              // 2x2 city dot covers two lines
    269               PrevMiniPixel.SetX(xm);
     283              PrevMiniPixel.SetX(XM);
    270284              if (PByte(PrevMiniPixel.Pixel) >= Bitmap.RawImage.Data) and
    271               (PByte(PrevMiniPixel.Pixel) < (Bitmap.RawImage.Data + yy * PrevMiniPixel.BytesPerLine)) then begin
    272                 PrevMiniPixel.PixelB := cm shr 16;
    273                 PrevMiniPixel.PixelG:= cm shr 8 and $FF;
    274                 PrevMiniPixel.PixelR := cm and $FF;
     285              (PByte(PrevMiniPixel.Pixel) < (Bitmap.RawImage.Data + YY * PrevMiniPixel.BytesPerLine)) then begin
     286                PrevMiniPixel.PixelB := CM shr 16;
     287                PrevMiniPixel.PixelG:= CM shr 8 and $FF;
     288                PrevMiniPixel.PixelR := CM and $FF;
    275289              end;
    276290            end;
    277291          end
    278           else if (i = 0) and (Tile and smUnit <> 0) then begin
    279             if Tile and smOwned <> 0 then cm := OwnColor
    280               else cm := EnemyColor;
     292          else if (I = 0) and (Tile and smUnit <> 0) then begin
     293            if Tile and smOwned <> 0 then CM := OwnColor
     294              else CM := EnemyColor;
    281295          end else
    282             cm := Colors[Tile and fTerrain, i];
     296            CM := Colors[Tile and fTerrain, I];
    283297          if (PByte(MiniPixel.Pixel) >= Bitmap.RawImage.Data) and
    284           (PByte(MiniPixel.Pixel) < (Bitmap.RawImage.Data + yy * MiniPixel.BytesPerLine)) then begin
    285             MiniPixel.PixelB := (cm shr 16) and $ff;
    286             MiniPixel.PixelG := (cm shr 8) and $ff;
    287             MiniPixel.PixelR := (cm shr 0) and $ff;
     298          (PByte(MiniPixel.Pixel) < (Bitmap.RawImage.Data + YY * MiniPixel.BytesPerLine)) then begin
     299            MiniPixel.PixelB := (CM shr 16) and $ff;
     300            MiniPixel.PixelG := (CM shr 8) and $ff;
     301            MiniPixel.PixelR := (CM shr 0) and $ff;
    288302          end;
    289303        end;
    290304      end;
    291305      MiniPixel.NextLine;
    292       if y > 0 then PrevMiniPixel.NextLine;
     306      if Y > 0 then PrevMiniPixel.NextLine;
    293307    end;
    294308    Bitmap.EndUpdate;
Note: See TracChangeset for help on using the changeset viewer.