unit UUoaDesigns; {$mode ObjFPC}{$H+} {$modeSwitch advancedRecords} interface uses Classes, SysUtils, Generics.Collections, UStatics; type { TUoaDesignHeader } TUoaDesignHeader = record Name: String; Category: String; Subcategory: String; Width: Int32; Height: Int32; UserWidth: Int32; UserHeight: Int32; FilePosition: Int64; TileCount: Int32; public constructor CreateFromStream(AStream: TStream); end; { TUoaDesignHeaders } TUoaDesignHeaders = class(specialize TList) constructor CreateFromStream(AStream: TStream); end; TUoaDesign = class private FHeader: TUoaDesignHeader; FTiles: TStaticItemList; constructor Create(AHeader: TUoaDesignHeader; AData: TStream); public property Header: TUoaDesignHeader read FHeader; property Tiles: TStaticItemList read Ftiles; destructor Destroy; override; end; { TUoaDesigns } TUoaDesigns = class private FHeaders: TUoaDesignHeaders; FData: TFileStream; public constructor Create(AIdxFile, ABinFile: String); destructor Destroy; override; function LoadDesign(AHeader: TUoaDesignHeader): TUoaDesign; public property Headers: TUoaDesignHeaders read FHeaders; end; implementation uses Math; function ReadString(AStream: TStream): String; var nonNullFlag: Byte; length: Byte; begin nonNullFlag := AStream.ReadByte; if nonNullFlag = 1 then begin length := AStream.ReadByte; SetLength(Result, length); if length > 0 then AStream.Read(PChar(Result)^, length); end; end; { TUoaDesign } constructor TUoaDesign.Create(AHeader: TUoaDesignHeader; AData: TStream); var i: Integer; tile: TStaticItem; version: Int32; function ReadInt: Int32; begin AData.Read(Result, SizeOf(Result)); end; begin FHeader := AHeader; FTiles := TStaticItemList.Create(True); AData.Seek(FHeader.FilePosition, soFromBeginning); for i := 0 to FHeader.TileCount - 1 do begin AData.Read(version, SizeOf(version)); if (version < 0) or (version > 1) then raise Exception.Create('Unsupported binary version'); tile := TStaticItem.Create(nil); tile.TileID := ReadInt; tile.X := ReadInt; tile.Y := ReadInt; tile.Z := EnsureRange(ReadInt, -128, 127); ReadInt; // Level; unused if version = 1 then tile.Hue := ReadInt; FTiles.Add(tile); end; end; destructor TUoaDesign.Destroy; begin FTiles.Free; inherited Destroy; end; { TUoaDesignHeaders } constructor TUoaDesignHeaders.CreateFromStream(AStream: TStream); var headerCount, version: Int32; i: Integer; begin AStream.Read(headerCount, SizeOf(headerCount)); AStream.Read(version, SizeOf(version)); if version <> 0 then raise Exception.Create('Unknown UOA design index version'); inherited Create; for i := 0 to headerCount-1 do Add(TUoaDesignHeader.CreateFromStream(AStream)); end; { TUoaDesignHeader } constructor TUoaDesignHeader.CreateFromStream(AStream: TStream); begin Name := ReadString(AStream); Category := ReadString(AStream); Subcategory := ReadString(AStream); AStream.Read(Width, SizeOf(Width)); AStream.Read(Height, SizeOf(Height)); AStream.Read(UserWidth, SizeOf(UserWidth)); AStream.Read(UserHeight, SizeOf(UserHeight)); AStream.Read(FilePosition, SizeOf(FilePosition)); AStream.Read(TileCount, SizeOf(TileCount)); end; { TUoaDesigns } constructor TUoaDesigns.Create(AIdxFile, ABinFile: String); var idxStream: TFileStream; begin idxStream := TFileStream.Create(AIdxFile, fmOpenRead); try FHeaders := TUoaDesignHeaders.CreateFromStream(idxStream); finally idxStream.Free; end; FData := TFileStream.Create(ABinFile, fmOpenRead); end; destructor TUoaDesigns.Destroy; begin Headers.Free; end; function TUoaDesigns.LoadDesign(AHeader: TUoaDesignHeader): TUoaDesign; begin Result := TUoaDesign.Create(AHeader, FData); end; end.